You are on page 1of 1086

Visual C# 3.

0
Application Design
II
FunctionX Press
SUMARY
QUERYING A LIST.................................................................................................................................20
THE LANGUAGE INTEGRATED QUERY.....................................................................................................20
Introduction to Querying...................................................................................................................20
Introduction to LINQ.........................................................................................................................20
Selecting the Values...........................................................................................................................21
Using a Collection-Based Variable...................................................................................................23
Using a Criterion to Create a Sub-List..............................................................................................24
OPERATIONS ON QUERIES.......................................................................................................................27
Using Logical Conjunctions and  Disjunctions.................................................................................27
Arranging the List..............................................................................................................................29
INFLUENCING A LINQ STATEMENT........................................................................................................31
Using the Primitive Types..................................................................................................................31
Using the String Class.......................................................................................................................32
LINQ AND CLASSES................................................................................................................................33
Using Built-In Classes.......................................................................................................................38
LINQ OPERATORS...................................................................................................................................38
Letting a Sub-List...............................................................................................................................38
Creating a new List............................................................................................................................40
EXPLORING THE LINQ........................................................................................................................42
THE IENUMERABLE GENERIC INTERFACE................................................................................................42
Using IEnumerable............................................................................................................................43
The Characteristics of IEnumerable..................................................................................................44
INTRODUCTION TO XML....................................................................................................................48
THE EXTENSIBLE MARKUP LANGUAGE..................................................................................................48
Overview of Files...............................................................................................................................48
Markup...............................................................................................................................................52
The Document Type Declaration (DTD)...........................................................................................52
Encoding Declaration........................................................................................................................52
Creating an XML File........................................................................................................................53
Practical Learning: Introducing XML...............................................................................................53
WRITING XML CODE..............................................................................................................................53
Writing XML Code Using XmlDocument..........................................................................................53
Practical Learning: Creating an XML Document.............................................................................54
Writing XML Code Using the Code Editor........................................................................................54
SAVING AN XML FILE............................................................................................................................55
Using the Wizard...............................................................................................................................55
Practical Learning: Creating the Root Tag.......................................................................................56
Saving a DOM Object........................................................................................................................56
OPENING AN XML FILE..........................................................................................................................57
An XML File in a Browser................................................................................................................57
Using a Style Sheet to Display an XML File in a Browser................................................................58
Programmatically Opening an XML File Using the DOM...............................................................59
Programmatically Reading an XML File..........................................................................................61
XML WELLFORMEDNESS........................................................................................................................64
Tag Creation......................................................................................................................................64
Practical Learning: Creating XML...................................................................................................65
Tag Names.........................................................................................................................................65
The Root.............................................................................................................................................66
THE STRUCTURE OF AN XML TAG.........................................................................................................69
Empty Tags........................................................................................................................................69
White Spaces......................................................................................................................................69
Nesting Tags......................................................................................................................................70
Practical Learning: Creating XML...................................................................................................70

C# 3.0 Practical Learning II 2


THE NODES OF AN XML ELEMENT.................................................................................................73
AN XML NODE.......................................................................................................................................73
Introduction to Node Types................................................................................................................74
ELEMENTS FUNDAMENTALS....................................................................................................................74
Practical Learning: Introducing XML Elements...............................................................................76
The Name of an Element....................................................................................................................77
The Text or Value of an Element.......................................................................................................79
Practical Learning: Getting the Text of an Element..........................................................................81
Empty Elements..................................................................................................................................82
Character Entities in an Element Value............................................................................................83
Practical Learning: Introducing XML Elements...............................................................................88
IDENTIFYING THE MARKUP OF A NODE..................................................................................................90
The Inner Text of a node....................................................................................................................90
The Outer XML Code of a node.........................................................................................................91
The Inner XML Code of a node.........................................................................................................92
THE  CHILD NODES OF  A NODE.............................................................................................................93
A Collection of Child Nodes..............................................................................................................93
Accessing a Node in a Collection......................................................................................................94
The Parent of a Node.........................................................................................................................97
The First Child Node.........................................................................................................................97
The Last Child Node........................................................................................................................102
The Siblings of a Node.....................................................................................................................102
OPERATIONS ON XML ELEMENTS................................................................................................104
FUNDAMENTAL OPERATIONS................................................................................................................104
Practical Learning: Introducing operations on XML Elements......................................................104
Adding an Empty Element................................................................................................................105
Adding an Element With Value........................................................................................................107
Practical Learning: Programmatically Adding an Element............................................................113
Adding a Filled Child Element........................................................................................................117
INSERTING AN ELEMENT.......................................................................................................................119
Locating an Element........................................................................................................................119
Inserting an Element as a Last Child...............................................................................................121
Practical Learning: Adding Elements.............................................................................................130
Insertion an Element Referencing a Sibling....................................................................................136
Node Removal..................................................................................................................................139
THE ATTRIBUTES OF AN XML ELEMENT...................................................................................142
FUNDAMENTALS OF ATTRIBUTES..........................................................................................................142
Practical Learning: Introducing Attributes.....................................................................................142
Creating an Attribute.......................................................................................................................143
OPERATIONS ON AN XML ATTRIBUTE...................................................................................................143
Manually Creating an Attribute.......................................................................................................144
Practical Learning: Creating Simple Attributes..............................................................................145
Programmatically Creating an Attribute.........................................................................................145
Practical Learning: Creating an Attribute......................................................................................148
The Parent of an Attribute...............................................................................................................150
Attribute Removal............................................................................................................................150
THE COLLECTION OF ATTRIBUTES OF AN ELEMENT.............................................................................151
Practical Learning: Adding Attributes............................................................................................151
Access to an Attribute......................................................................................................................152
Practical Learning: Accessing an Attribute....................................................................................153
Attribute Addition............................................................................................................................155
Practical Learning: Creating Attributes..........................................................................................155
Attribute Removal............................................................................................................................167
CHARACTERISTICS OF XML NODES.............................................................................................168
OVERVIEW OF TYPES OF NODES...........................................................................................................168
Comments.........................................................................................................................................168

C# 3.0 Practical Learning II 3


CDATA.............................................................................................................................................170
XML Serialization............................................................................................................................171
INTRODUCTION TO DATA SETS AND TABLES...........................................................................173
A SET OF DATA.....................................................................................................................................173
Data Set Creation............................................................................................................................173
TABLES FUNDAMENTALS......................................................................................................................175
Introduction to Tables......................................................................................................................175
Practical Learning: Introducing Tables..........................................................................................176
Creating a Table..............................................................................................................................176
THE TABLES OF A DATA SET................................................................................................................178
Accessing a Table in the Collection.................................................................................................178
Adding a New Table to a Collection................................................................................................180
Creating a Range of Tables.............................................................................................................182
Practical Learning: Creating Tables...............................................................................................182
Locating a Table in a Collection.....................................................................................................183
Practical Learning: Showing Tables...............................................................................................188
TABLES MAINTENANCE.........................................................................................................................190
Deleting a Table...............................................................................................................................190
Checking the Existence of a Table in a Collection..........................................................................192
Clearing a Collection of Tables.......................................................................................................194
THE COLUMNS OF A TABLE............................................................................................................195
FUNDAMENTALS OF COLUMNS OF A TABLE...........................................................................................195
Practical Learning: Introducing Columns......................................................................................196
Creating a Column...........................................................................................................................197
OPERATIONS ON THE COLUMNS OF A TABLE.........................................................................................199
Adding a Column to a Table............................................................................................................199
Practical Learning: Creating Columns...........................................................................................201
Adding an Array of Columns...........................................................................................................202
Specifying the Type of Data of a Column........................................................................................203
Practical Learning: Specifying the Data Types of Columns Columns............................................204
COLUMNS MAINTENANCE.....................................................................................................................206
The Parent Table of a Column.........................................................................................................206
Identifying a Column.......................................................................................................................206
Practical Learning: Listing the Columns of a table........................................................................207
DELETING COLUMNS.............................................................................................................................211
Deleting a Column by Name............................................................................................................211
Deleting a Column by Index............................................................................................................215
Clearing the Table of Columns........................................................................................................216
THE RECORDS OF A TABLE.............................................................................................................217
THE ROWS OF A TABLE.........................................................................................................................217
Introduction to Records...................................................................................................................217
Practical Learning: Introducing Data Records...............................................................................218
The Row of a Table..........................................................................................................................218
Introduction to Data Entry..............................................................................................................219
DATA ENTRY.........................................................................................................................................219
Adding a Record to a Table.............................................................................................................220
Adding an Array of Records............................................................................................................221
The Number of Records of a Table..................................................................................................223
SAVING THE RECORDS OF A TABLE......................................................................................................223
Saving a Data Set.............................................................................................................................223
Practical Learning: Creating a Data Set........................................................................................226
Opening a Data Set..........................................................................................................................234
Committing or Rejecting Changes to a List.....................................................................................237
LOCATING RECORDS AND THEIR VALUES............................................................................................237
Locating a Record............................................................................................................................237
Locating a Value..............................................................................................................................240
Practical Learning: Getting the Values of a Data Set.....................................................................245

C# 3.0 Practical Learning II 4


RECORDS MANAGEMENT.................................................................................................................254
RECORDS MAINTENANCE......................................................................................................................254
Editing a Record by the Columns' Object Names............................................................................255
Editing a Record by the Columns' Indices.......................................................................................261
DELETING RECORDS..............................................................................................................................262
Deleting the Current Row................................................................................................................262
Removing a Row From the Collection of Records...........................................................................264
Deleting a Record by its Index.........................................................................................................266
Deleting all Records of a Table.......................................................................................................266
DATA RELATIONSHIPS...........................................................................................................................267
Table Preparation............................................................................................................................267
Creating a Relationship...................................................................................................................272
INTRODUCTION TO ADO...................................................................................................................281
ADO FUNDAMENTALS..........................................................................................................................281
Introduction to Databases...............................................................................................................281
Microsoft JET..................................................................................................................................281
Referencing a Library in a .NET Framework..................................................................................282
MICROSOFT ADO EXT..........................................................................................................................282
The Catalog Class............................................................................................................................283
DATABASE CREATION...........................................................................................................................284
The Catalog Class............................................................................................................................284
The Provider....................................................................................................................................284
The Data Source of a Connection String.........................................................................................286
The ODBC Data Source..................................................................................................................287
USING THE MICROSOFT ACTIVEX DATA OBJECTS (ADO)...................................................................289
Referencing ADO.............................................................................................................................290
The ADODB Namespace.................................................................................................................290
THE CONNECTION TO A DATABASE......................................................................................................291
Opening a Connection.....................................................................................................................291
The Connection String.....................................................................................................................292
The Login Credentials.....................................................................................................................293
Executing a SQL Statement..............................................................................................................294
Closing a Connection.......................................................................................................................295
THE RECORDS OF A DATABASE.....................................................................................................298
TABLE CREATION..................................................................................................................................298
Table Creation.................................................................................................................................298
The Name of a Table........................................................................................................................299
TABLE MAINTENANCE...........................................................................................................................300
The Tables Collection......................................................................................................................300
Deleting a Table...............................................................................................................................300
COLUMNS FUNDAMENTALS...................................................................................................................301
Column Creation..............................................................................................................................302
CHARACTERISTICS OF A COLUMN.........................................................................................................302
The Types of Columns......................................................................................................................303
COLUMN MAINTENANCE.......................................................................................................................308
Adding a New Column.....................................................................................................................308
Deleting a Column...........................................................................................................................309
DATA ENTRY FUNDAMENTALS.............................................................................................................310
New Record Creation.......................................................................................................................311
Adjacent Data entry.........................................................................................................................312
Random Data Entry.........................................................................................................................313
DATA ENTRY ASSISTANCE....................................................................................................................314
The Nullity of a Field.......................................................................................................................314
Auto-Increment................................................................................................................................315
Fields Sizes......................................................................................................................................317
Default Values..................................................................................................................................317
MATHEMATICS IN C#.........................................................................................................................319

C# 3.0 Practical Learning II 5


OVERVIEW OF NUMBERS.......................................................................................................................319
The Sign of a Number......................................................................................................................319
The Integral Side of a Floating-Point Number................................................................................321
The Minimum of Two Values...........................................................................................................322
The Maximum Integer Value of a Series..........................................................................................323
VALUE CONVERSIONS...........................................................................................................................323
Implicit Conversions........................................................................................................................324
Explicit Conversions........................................................................................................................325
The Convert Class............................................................................................................................327
ARITHMETIC..........................................................................................................................................329
Absolute Values................................................................................................................................329
The Ceiling of a Number..................................................................................................................330
The Floor of a Number....................................................................................................................331
The Power of a Number...................................................................................................................331
The Exponential...............................................................................................................................332
The Natural Logarithm....................................................................................................................333
The Base 10 Logarithm....................................................................................................................333
The Logarithm of Any Base.............................................................................................................334
The Square Root...............................................................................................................................335
TRIGONOMETRY.....................................................................................................................................335
The Pi Constant...............................................................................................................................336
The Cosine of a Value......................................................................................................................337
The Sine of a Value..........................................................................................................................338
Tangents...........................................................................................................................................338
The Arc Tangent...............................................................................................................................339
DATES AND TIMES..............................................................................................................................341
DATES AND TIMES.................................................................................................................................341
Date Time Value Creation...............................................................................................................342
The Characteristics of a Date-Time Value......................................................................................343
The Default Date and Time Values..................................................................................................343
DATES....................................................................................................................................................344
Date Creation..................................................................................................................................344
Converting a String to Date.............................................................................................................345
Rules of Date Formats.....................................................................................................................345
DATE FORMATS.....................................................................................................................................350
The Computer’s System of Displaying Dates..................................................................................350
Getting a Date Value From a DateTime Object..............................................................................350
The Short Date.................................................................................................................................352
The Long Date Format....................................................................................................................354
Other Date Formats.........................................................................................................................355
OPERATIONS ON DATES.........................................................................................................................356
The Leap Year..................................................................................................................................356
The Day of the Week........................................................................................................................357
A Time Span.....................................................................................................................................358
Adding and/or Subtracting Days.....................................................................................................358
Adding or Subtracting Months to a Date.........................................................................................360
Adding or Subtracting Years to a Date............................................................................................360
Logical Operations on Dates...........................................................................................................361
TIME......................................................................................................................................................361
Creating a Time Value.....................................................................................................................363
Retrieving a Time Value..................................................................................................................364
THE CHARACTERISTICS OF A TIME VALUE...........................................................................................365
The Components of a Time..............................................................................................................365
The Time of Day of a DateTime Value............................................................................................365
OPERATIONS ON TIME VALUES.............................................................................................................366
Converting a Time Value to a String...............................................................................................366
Time Rules and Formats..................................................................................................................367
Comparison Operations On Time Values........................................................................................375
COMBINING DATE AND TIME................................................................................................................375

C# 3.0 Practical Learning II 6


The Current Date and Time.............................................................................................................375
Formatting Date and Time Combinations.......................................................................................376
WINDOWS CONTROL: THE BUTTON.............................................................................................377
DESCRIPTION.........................................................................................................................................377
CREATING A BUTTON............................................................................................................................381
THE CHARACTERISTICS OF A BUTTON.......................................................................................382
THE CAPTION OF A BUTTON..................................................................................................................382
THE IMAGE ON A BUTTON.....................................................................................................................388
THE FLAT STYLE OF A BUTTON............................................................................................................390
THE RESULT OF A DIALOG BOX............................................................................................................390
Applications:....................................................................................................................................391
WINDOWS CONTROL: THE COMBO BOX....................................................................................392
DESCRIPTION.........................................................................................................................................392
CREATING A COMBO BOX.....................................................................................................................393
THE COMBO BOX: CREATING AND SELECTING ITEMS..........................................................................400
CREATING THE LIST OF ITEMS..............................................................................................................400
SELECTING AN ITEM..............................................................................................................................402
FINDING A STRING IN THE COMBO BOX................................................................................................422
THE STYLES OF A COMBO BOX......................................................................................................423
THE FLAT STYLES.................................................................................................................................423
THE DROP DOWN STYLE.......................................................................................................................425
THE DROP DOWN LIST..........................................................................................................................429
THE SIMPLE COMBO BOX......................................................................................................................429
THE COMBO BOX: AUTOMATIC LIST CREATION....................................................................431
USING AN EXTERNAL LIST....................................................................................................................431
USING A CUSTOM LIST..........................................................................................................................433
ACCESSORIES FOR CONTROL DESIGN: THE FLOW LAYOUT PANEL...............................434
INTRODUCTION......................................................................................................................................434
CHARACTERISTICS OF THE FLOW LAYOUT PANEL................................................................................435
THE CHARACTERISTICS OF A BUTTON.......................................................................................436
THE CAPTION OF A BUTTON..................................................................................................................436
THE IMAGE ON A BUTTON.....................................................................................................................442
THE FLAT STYLE OF A BUTTON............................................................................................................443
THE RESULT OF A DIALOG BOX............................................................................................................443
Applications:....................................................................................................................................444
WINDOWS CONTROL: THE LINK LABEL.....................................................................................445
INTRODUCTION......................................................................................................................................445
CHARACTERISTICS OF THE LINK LABEL................................................................................................445
WINDOWS CONTROL: THE MONTH CALENDAR......................................................................446
DESCRIPTION.........................................................................................................................................446
CREATING A CALENDAR........................................................................................................................448
USING A MONTH CALENDAR CONTROL.....................................................................................456
SELECTING A DATE...............................................................................................................................456
THE DATE RANGE SELECTION..............................................................................................................457
THE MAXIMUM DATE RANGE SELECTION............................................................................................462
WINDOWS CONTROLS: THE PICTURE BOX................................................................................463
DESCRIPTION.........................................................................................................................................463
GETTING A PICTURE BOX......................................................................................................................463
INTRODUCTION......................................................................................................................................464

C# 3.0 Practical Learning II 7


THE BORDER STYLE OF A PICTURE BOX...............................................................................................465
THE IMAGE OF A PICTURE BOX.............................................................................................................465
THE IMAGE LOCATION OF THE IMAGE OF A PICTURE BOX...................................................................467
THE SIZE MODE OF A PICTURE BOX.....................................................................................................469
WINDOWS CONTROL: RICH TEXT BOX.......................................................................................477
DESCRIPTION.........................................................................................................................................477
CREATING A RICH TEXT CONTROL.......................................................................................................477
INTRODUCTION......................................................................................................................................482
SAVING THE CONTENTS OF A RICH TEXT DOCUMENT..........................................................................483
OPENING A RICH TEXT FILE..................................................................................................................484
FORMATTING TEXT................................................................................................................................490
THE PARAGRAPH ALIGNMENT..............................................................................................................491
THE INDENTATION OF A PARAGRAPH....................................................................................................492
A BULLETED PARAGRAPH.....................................................................................................................493
ACCESSORIES FOR CONTROL DESIGN: THE TABLE LAYOUT PANEL..............................494
INTRODUCTION......................................................................................................................................494
CHARACTERISTICS OF A TABLE LAYOUT..............................................................................................495
THE CHARACTERISTICS OF A BUTTON.......................................................................................496
THE CAPTION OF A BUTTON..................................................................................................................496
THE IMAGE ON A BUTTON.....................................................................................................................502
THE FLAT STYLE OF A BUTTON............................................................................................................503
THE RESULT OF A DIALOG BOX............................................................................................................504
Applications:....................................................................................................................................505
THE BROWSE FOR FOLDER DIALOG BOX..................................................................................505
DESCRIPTION.........................................................................................................................................505
CREATING A BROWSE FOR FOLDER DIALOG BOX................................................................................506
CHARACTERISTICS OF THE BROWSE FOR FOLDER DIALOG BOX....................................508
THE DESCRIPTION..................................................................................................................................508
THE ROOT FOLDER................................................................................................................................509
THE SELECTED PATH.............................................................................................................................510
THE MAKE NEW FOLDER BUTTON.......................................................................................................511
APPLICATION MENUS: CONTEXTUAL MENUS..........................................................................512
INTRODUCTION......................................................................................................................................512
CREATING A CONTEXTUAL MENU........................................................................................................514
USING A CONTEXTUAL MENU...............................................................................................................518
CODING CONTEXTUAL MENUS..............................................................................................................520
THE FONT DIALOG BOX....................................................................................................................524
INTRODUCTION......................................................................................................................................525
CREATING A FONT DIALOG BOX...........................................................................................................526
THE FONT OF A FONT DIALOG BOX......................................................................................................528
THE APPLY BUTTON..............................................................................................................................529
THE EFFECTS OF A FONT DIALOG BOX.................................................................................................530
THE COLOR COMBO BOX......................................................................................................................530
WINDOWS CONTROL: THE LIST BOX...........................................................................................532
DESCRIPTION.........................................................................................................................................532
CREATING A LIST BOX..........................................................................................................................533
THE ITEMS OF A LIST BOX...............................................................................................................538
INTRODUCTION......................................................................................................................................538
ADDING ITEMS TO A LIST BOX.............................................................................................................538
SELECTING AN ITEM IN A LIST BOX......................................................................................................546
REMOVING ITEMS FROM A LIST BOX....................................................................................................558

C# 3.0 Practical Learning II 8


SORTING A LIST BOX............................................................................................................................560
CHARACTERISTICS OF A LIST BOX..............................................................................................561
THE SCROLL BARS................................................................................................................................561
A MULTI-COLUMN LIST BOX................................................................................................................565
A CUSTOM OWNER-DRAW LIST BOX...................................................................................................565
WINDOWS CONTROL: THE NUMERIC UP-DOWN......................................................................566
DESCRIPTION.........................................................................................................................................566
CREATING AN UP-DOWN CONTROL......................................................................................................566
CHARACTERISTICS OF THE NUMERIC UP-DOWN CONTROL..............................................567
THE UP-DOWN ALIGNMENT..................................................................................................................567
INTERCEPTING THE ARROW KEYS.........................................................................................................568
THE MINIMUM AND THE MAXIMUM VALUES.......................................................................................568
THE VALUE OF THE CONTROL...............................................................................................................569
THE TYPE OF VALUE.............................................................................................................................569
DISPLAYING DECIMAL NUMBERS..........................................................................................................570
THE THOUSAND SEPARATOR.................................................................................................................570
THE INCREMENTING VALUE..................................................................................................................570
Applications:....................................................................................................................................571
THE PRINT DIALOG BOX...................................................................................................................571
INTRODUCTION......................................................................................................................................571
PROVIDING A PRINTER..........................................................................................................................572
THE DOCUMENT TO PRINT....................................................................................................................573
EVENTS RELATED TO PRINTING............................................................................................................575
THE PRINTER SETTINGS.........................................................................................................................575
THE SAVE DIALOG BOX....................................................................................................................579
DESCRIPTION.........................................................................................................................................579
SAVE AS DIALOG BOX CREATION........................................................................................................581
CHARACTERISTICS OF THE SAVE AS DIALOG BOX................................................................582
THE FILE EXTENSION............................................................................................................................582
THE FILTER............................................................................................................................................582
THE FILTER INDEX................................................................................................................................584
THE DEFAULT EXTENSION....................................................................................................................585
DISPLAYING THE DIALOG BOX.............................................................................................................586
WINDOWS CONTROL: THE TEXT BOX.........................................................................................587
INTRODUCTION......................................................................................................................................588
CREATING A TEXT BOX.........................................................................................................................588
INTRODUCTION......................................................................................................................................588
SELECTING TEXT...................................................................................................................................589
OPERATIONS ON TEXT...........................................................................................................................589
MNEMONICS..........................................................................................................................................590
THE READ-ONLY ATTRIBUTE...............................................................................................................590
AUTO-COMPLETING A TEXT BOX.........................................................................................................591
CHARACTER CASING.............................................................................................................................591
CHARACTER PASSWORD........................................................................................................................591
INTRODUCTION......................................................................................................................................592
CREATING A MULTI-LINE TEXT BOX....................................................................................................592
INTRODUCTION......................................................................................................................................592
THE LINES OF TEXT...............................................................................................................................593
THE MODIFIED ATTRIBUTE...................................................................................................................593
THE MAXIMUM LENGTH OF TEXT.........................................................................................................593
USING THE ENTER KEY.........................................................................................................................593
USING THE TAB KEY.............................................................................................................................594
WRAPPING TEXT...................................................................................................................................594

C# 3.0 Practical Learning II 9


USING SCROLL BARS.............................................................................................................................595
METHODS TO MANAGE A MULTI-LINE TEXT BOX...............................................................................595
Application.......................................................................................................................................596
WINDOWS CONTROLS: THE TRACK BAR....................................................................................596
INTRODUCTION......................................................................................................................................596
CREATING A TRACK BAR......................................................................................................................598
CHARACTERISTICS OF A TRACK BAR.........................................................................................599
THE ORIENTATION.................................................................................................................................599
THE VALUE OF A TRACK BAR...............................................................................................................600
THE MAXIMUM AND THE MINIMUM VALUES.......................................................................................601
THE TICKS OF A TRACK BAR................................................................................................................602
THE TICK FREQUENCY..........................................................................................................................603
THE TICK STYLE....................................................................................................................................603
THE SMALL CHANGE.............................................................................................................................604
THE LARGE CHANGE.............................................................................................................................604
Applications:....................................................................................................................................605
WINDOWS CONTROLS: CHECK BOXES........................................................................................605
INTRODUCTION......................................................................................................................................605
CREATING A CHECK BOX......................................................................................................................606
WINDOWS CONTROLS: CHECK BOXES........................................................................................614
CHECKING A CHECK BOX......................................................................................................................614
THE ALIGNMENT OF A CHECK BOX......................................................................................................622
THE CHECKED STATE OF A CHECK BOX...............................................................................................622
THE APPEARANCE OF A CHECK BOX....................................................................................................623
Applications.....................................................................................................................................624
WINDOWS CONTROL: THE DATA GRID VIEW...........................................................................624
INTRODUCTION......................................................................................................................................624
CREATING A DATA GRID VIEW.............................................................................................................625
INTRODUCTION......................................................................................................................................627
CREATING A COLUMN...........................................................................................................................628
DELETING A COLUMN...........................................................................................................................629
THE CELL TEMPLATE OF A COLUMN....................................................................................................630
THE NAME OF A COLUMN.....................................................................................................................635
THE CAPTION OF A COLUMN.................................................................................................................636
THE WIDTH OF A COLUMN....................................................................................................................638
REFERRING TO A COLUMN....................................................................................................................639
INTRODUCTION TO ROWS......................................................................................................................640
THE ROWS OF A DATA GRID VIEW.......................................................................................................641
THE HEIGHT OF A ROW.........................................................................................................................643
INTRODUCTION......................................................................................................................................643
THE CELLS OF A ROW...........................................................................................................................644
THE VALUE OF A CELL..........................................................................................................................645
CREATING A RECORD............................................................................................................................648
WINDOWS CONTROL: THE GROUP BOX......................................................................................650
DESCRIPTION.........................................................................................................................................650
GROUP BOX CREATION.........................................................................................................................650
THE CAPTION OF A GROUP BOX...........................................................................................................652
THE GROUP BOX AS A CONTAINER.......................................................................................................652
AUTOMATICALLY RESIZING A GROUP BOX..........................................................................................653
GIVING FOCUS TO A GROUP BOX..........................................................................................................654
USING A MNEMONIC.............................................................................................................................654
WINDOWS CONTROL: THE LIST VIEW........................................................................................655
INTRODUCTION......................................................................................................................................655

C# 3.0 Practical Learning II 10


LIST VIEW CREATION............................................................................................................................655
VISUALLY CREATING THE ITEMS OF A LIST VIEW................................................................657
THE MAIN ITEMS OF THE LIST VIEW....................................................................................................657
VIEW STYLES........................................................................................................................................659
LIST VIEW ITEMS AND THEIR ICONS.....................................................................................................663
THE COLUMNS OF A LIST VIEW.....................................................................................................670
INTRODUCTION......................................................................................................................................670
VISUALLY CREATING COLUMNS...........................................................................................................671
PROGRAMMATICALLY CREATING COLUMNS.........................................................................................671
COLUMN INSERTION..............................................................................................................................676
THE NUMBER OF COLUMNS OF A LIST VIEW........................................................................................678
LOCATING COLUMNS.............................................................................................................................678
DELETING COLUMNS.............................................................................................................................678
THE ITEMS OF A LIST VIEW............................................................................................................679
ADDING AN ITEM TO THE LIST VIEW....................................................................................................679
ADDING AN ARRAY OF ITEMS...............................................................................................................683
USING A LIST VIEW.............................................................................................................................685
SELECTING AN ITEM FROM THE LIST VIEW..........................................................................................685
EDITING A LABEL..................................................................................................................................685
ACTIVATING AN ITEM............................................................................................................................686
USING COLUMNS...................................................................................................................................688
IDENTIFYING AN ITEM...........................................................................................................................688
THE SUB ITEMS OF AN ITEM...........................................................................................................688
INTRODUCTION......................................................................................................................................688
VISUALLY CREATING SUB ITEMS..........................................................................................................690
PROGRAMMATICALLY CREATING SUB ITEMS.......................................................................................692
MANAGING SUB ITEMS..........................................................................................................................701
MANAGING THE ITEMS OF A LIST VIEW....................................................................................703
THE FONT, TEXT COLOR, AND BACKGROUND OF AN ITEM..................................................................703
LOCATING A LIST VIEW ITEM...............................................................................................................706
DELETING ITEMS...................................................................................................................................707
CHARACTERISTICS OF A LIST VIEW............................................................................................707
COLUMN HEADER STYLE......................................................................................................................707
SELECTING ITEMS IN A LIST VIEW........................................................................................................709
FULL ROW SELECTION..........................................................................................................................710
GRID LINES............................................................................................................................................710
LIST ITEMS AND CHECK BOXES............................................................................................................710
THE OPEN DIALOG BOX....................................................................................................................711
DESCRIPTION.........................................................................................................................................711
OPEN FILE DIALOG BOX CREATION......................................................................................................712
CHARACTERISTICS OF THE OPEN DIALOG BOX.....................................................................713
THE FILENAME......................................................................................................................................713
THE FILTER............................................................................................................................................713
THE FILTER INDEX................................................................................................................................714
SHOWING THE DIALOG BOX..................................................................................................................714
OPENING VARIOUS FILES......................................................................................................................714
OPENING A FILE AS READ-ONLY..........................................................................................................715
PRINT PREVIEW...................................................................................................................................716
INTRODUCTION......................................................................................................................................716
PROVIDING PRINT PREVIEW..................................................................................................................716

C# 3.0 Practical Learning II 11


CHARACTERISTICS OF THE PRINT PREVIEW...........................................................................718
THE PREVIEW AREA..............................................................................................................................718
PRINTING FROM THE PRINT PREVIEW...................................................................................................721
ZOOMING THE PREVIEW........................................................................................................................722
A DOCUMENT OF VARIOUS PAGES.......................................................................................................722
WINDOWS CONTROL: SCROLL BARS...........................................................................................723
DESCRIPTION.........................................................................................................................................723
AUTOMATICALLY-ADDED SCROLL BARS..............................................................................................724
SCROLL BARS UPON REQUEST..............................................................................................................725
TEXT-BASED APPLICATIONS AND SCROLL BARS..................................................................................726
INTRODUCTION......................................................................................................................................726
CREATING A SCROLL BAR CONTROL....................................................................................................726
THE MINIMUM AND MAXIMUM.............................................................................................................727
THE VALUE OF A SCROLL BAR.............................................................................................................727
THE SMALL CHANGE.............................................................................................................................728
THE LARGE CHANGE.............................................................................................................................728
WINDOWS CONTROL: THE SCROLL BARS..................................................................................729
INTRODUCTION......................................................................................................................................729
CREATING A SCROLL BAR CONTROL....................................................................................................729
THE MINIMUM AND MAXIMUM.............................................................................................................729
THE VALUE OF A SCROLL BAR.............................................................................................................730
THE SMALL CHANGE.............................................................................................................................731
THE LARGE CHANGE.............................................................................................................................731
WINDOWS CONTROL: THE TICK COUNTER..............................................................................731
INTRODUCTION......................................................................................................................................731
WINDOWS CONTROL: CHECKED LIST BOXES..........................................................................735
DESCRIPTION.........................................................................................................................................735
CREATING A CHECKED LIST BOX.........................................................................................................738
CHARACTERISTICS OF A CHECKED LIST BOX.........................................................................741
INTRODUCTION......................................................................................................................................741
CREATING THE LIST OF ITEMS..............................................................................................................741
CHECKING AN ITEM...............................................................................................................................743
AUTOMATICALLY CHECKING AN ITEM WHEN CLICKED.......................................................................751
3-D CHECKED ITEMS.............................................................................................................................751
WINDOWS CONTROL: THE DATE PICKER CONTROL.............................................................752
INTRODUCTION TO THE DATE PICKER CONTROL..................................................................................752
CREATING A DATE/TIME PICKER..........................................................................................................753
INTRODUCTION TO THE DATE PICKER...................................................................................................753
CHARACTERISTICS OF THE DATE PICKER................................................................................753
THE SPIN BUTTON.................................................................................................................................753
THE CHECK BOX...................................................................................................................................754
USING THE DATE PICKER......................................................................................................................755
THE CALENDAR VISUAL CHARACTERISTICS.........................................................................................756
THE ALIGNMENT OF THE CALENDAR....................................................................................................756
THE MINIMUM AND THE MAXIMUM DATES..........................................................................................757
THE VALUE OF THE CALENDAR............................................................................................................757
THE CUSTOM FORMAT OF THE CALENDAR...........................................................................................757
WINDOWS CONTROLS: AN IMAGE LIST......................................................................................758
INTRODUCTION......................................................................................................................................758
CREATING AN IMAGE LIST....................................................................................................................759
THE SIZE OF THE IMAGES......................................................................................................................761

C# 3.0 Practical Learning II 12


THE COLOR DEPTH................................................................................................................................763
CREATING THE COLLECTION OF IMAGES..............................................................................................764
USING AN IMAGE LIST...........................................................................................................................767
THE TRANSPARENT COLOR...................................................................................................................769
WINDOWS CONTROL: MASKED TEXT BOX................................................................................769
INTRODUCTION......................................................................................................................................769
MASKEDIT CHARACTERISTICS..............................................................................................................769
THE PAGE SETUP DIALOG BOX......................................................................................................773
INTRODUCTION......................................................................................................................................773
CHARACTERISTICS OF THE PAGE SETUP DIALOG BOX.........................................................................774
WINDOWS CONTROL: THE PROGRESS BAR...............................................................................776
DESCRIPTION.........................................................................................................................................776
CREATING A PROGRESS BAR.................................................................................................................776
CHARACTERISTICS OF A PROGRESS BAR..................................................................................777
INTRODUCTION......................................................................................................................................777
THE MINIMUM AND MAXIMUM.............................................................................................................778
THE VALUE OF A PROGRESS BAR.........................................................................................................778
THE STEP VALUE OF A PROGRESS BAR................................................................................................780
THE STYLE OF A PROGRESS BAR..........................................................................................................781
WINDOWS CONTROL: THE SPLIT CONTAINER.........................................................................782
INTRODUCTION......................................................................................................................................782
CREATING A SPLITTER...........................................................................................................................783
INTRODUCTION......................................................................................................................................785
THE BACKGROUND OF A SPLIT CONTAINER.........................................................................................785
THE SIZE OF THE SPLITTER...................................................................................................................785
THE ORIENTATION OF THE SPLITTER....................................................................................................785
MOVING THE SPLITTER.........................................................................................................................786
THE SPLITTER INCREMENT....................................................................................................................786
FIXING A PANEL....................................................................................................................................786
WINDOWS CONTROL: THE TIMER................................................................................................787
INTRODUCTION......................................................................................................................................787
CHARACTERISTICS OF A TIMER.............................................................................................................789
WINDOWS CONTROL: THE TREE VIEW.......................................................................................797
INTRODUCTION......................................................................................................................................797
TREE VIEW CREATION..........................................................................................................................798
INTRODUCTION TO CREATING TREE VIEW NODES...............................................................804
VISUALLY CREATING NODES................................................................................................................804
PROGRAMMATICALLY CREATING NODES..............................................................................................805
A NODE AND ITS CHILDREN............................................................................................................809
INTRODUCTION......................................................................................................................................809
CREATING CHILD NODES......................................................................................................................812
THE NUMBER OF CHILD NODES............................................................................................................821
THE NODES OF A NODE.........................................................................................................................822
NODE SELECTION..................................................................................................................................822
NODE EDITION.......................................................................................................................................823
NODE LOCATION...................................................................................................................................823
DELETING NODES..................................................................................................................................837
CHARACTERISTICS OF A TREE VIEW..........................................................................................838
THE PATH TO A NODE...........................................................................................................................838
HOT TRACKING.....................................................................................................................................839

C# 3.0 Practical Learning II 13


THE INTERMEDIARY LINES OF RELATED NODES..................................................................................839
THE ROOT LINES...................................................................................................................................840
NODE INDENTATION..............................................................................................................................841
FULL ROW SELECTION..........................................................................................................................841
HIDING SELECTION AFTER LOSING FOCUS...........................................................................................842
THE + AND - BUTTONS..........................................................................................................................842
EXPANDING AND COLLAPSING TREE NODES........................................................................................842
TREE NODES AND CHECK BOXES..........................................................................................................843
TREE NODES AND ICONS.......................................................................................................................844
WINDOWS CONTROLS: THE COLOR DIALOG BOX..................................................................853
INTRODUCTION......................................................................................................................................853
MAKING A COLOR DIALOG BOX AVAILABLE.......................................................................................855
THE COLOR PRODUCED BY A COLOR DIALOG BOX..............................................................................855
THE FULL VIEW OF A COLOR DIALOG BOX..........................................................................................856
SETTING THE COLOR OF, OR PAINTING, A PIXEL..................................................................................857
GETTING THE COLOR OF A PIXEL..........................................................................................................859
WINDOWS CONTROL: THE DOMAIN UP-DOWN........................................................................859
DESCRIPTION.........................................................................................................................................859
CREATING A DOMAIN UP-DOWN CONTROL..........................................................................................860
CHARACTERISTICS OF THE NUMERIC UP-DOWN CONTROL..............................................861
THE UP-DOWN ALIGNMENT..................................................................................................................861
INTERCEPTING THE ARROW KEYS.........................................................................................................862
THE MINIMUM AND THE MAXIMUM VALUES.......................................................................................862
THE VALUE OF THE CONTROL...............................................................................................................863
THE TYPE OF VALUE.............................................................................................................................863
DISPLAYING DECIMAL NUMBERS..........................................................................................................863
THE THOUSAND SEPARATOR.................................................................................................................863
THE INCREMENTING VALUE..................................................................................................................864
Applications:....................................................................................................................................864
WINDOWS CONTROL: THE LABEL................................................................................................865
DESCRIPTION.........................................................................................................................................865
CREATING A LABEL...............................................................................................................................865
THE CAPTION........................................................................................................................................866
AUTOMATICALLY SIZING A LABEL.......................................................................................................868
CONTENT ALIGNMENT...........................................................................................................................869
PICTURES ON A LABEL..........................................................................................................................870
A LABEL'S MNEMONIC..........................................................................................................................870
APPLICATION MENUS: THE MAIN MENU....................................................................................876
INTRODUCTION......................................................................................................................................876
MAIN MENU CREATION.........................................................................................................................877
MENU CATEGORIES...............................................................................................................................878
INTRODUCTION TO MENU ITEMS...........................................................................................................882
ASSOCIATING MENU ITEMS TO MENU CATEGORIES.............................................................................884
ASSOCIATING MENU CATEGORIES TO THE MAIN MENU......................................................................886
CODING A MENU ITEM..........................................................................................................................894
WINDOWS CONTROL: THE PANEL CONTROL...........................................................................896
INTRODUCTION......................................................................................................................................896
CREATING A PANEL...............................................................................................................................896
CHARACTERISTICS OF A PANEL.............................................................................................................897
WINDOWS CONTROL: THE RADIO BUTTONS............................................................................899
DESCRIPTION.........................................................................................................................................899
CREATING RADIO BUTTONS..................................................................................................................899
THE LOCATION OF A RADIO BUTTON...................................................................................................900

C# 3.0 Practical Learning II 14


THE CAPTION OF A RADIO BUTTON......................................................................................................901
CHECKING A RADIO BUTTON................................................................................................................902
THE ALIGNMENT OF A RADIO BUTTON.................................................................................................903
THE APPEARANCE OF A RADIO BUTTON...............................................................................................903
Applications:....................................................................................................................................906
TAB CONTROLS AND TAB PAGES..................................................................................................906
DESCRIPTION.........................................................................................................................................906
TAB CONTROL CREATION.....................................................................................................................909
THE TAB PAGES OF A TAB CONTROL..........................................................................................910
INTRODUCTION......................................................................................................................................910
CREATING A TAB PAGE.........................................................................................................................910
REMOVING A TAB PAGE........................................................................................................................915
TAB CONTROL AND TAB PAGE SELECTION...............................................................................916
TAB CONTROL SELECTION....................................................................................................................916
TAB PAGE SELECTION...........................................................................................................................917
THE TAB OF A TAB PAGE..................................................................................................................918
INTRODUCTION......................................................................................................................................918
THE CAPTION OF A TAB........................................................................................................................919
HOT TRACKING THE CAPTION OF A TAB PAGE.....................................................................................921
PADDING THE CAPTION OF A TAB PAGE...............................................................................................922
THE TOOL TIP OF A TAB PAGE.............................................................................................................922
A PICTURE ON A TAB............................................................................................................................922
MANAGING THE TABS.......................................................................................................................925
THE NAVIGATION ARROWS OF A TAB CONTROL..................................................................................925
A TAB CONTROL WITH MULTI-LINE....................................................................................................926
THE SIZE MODE.....................................................................................................................................926
THE TABS SIZE......................................................................................................................................929
THE ALIGNMENT OF TABS.....................................................................................................................929
THE APPEARANCE OF THE TABS...........................................................................................................931
WINDOWS CONTROL: THE TIMER................................................................................................932
INTRODUCTION......................................................................................................................................932
CHARACTERISTICS OF A TIMER.............................................................................................................934
THE FORMS OF AN APPLICATION: INTRODUCTION...............................................................942
INTRODUCTION......................................................................................................................................942
FORM CREATION...................................................................................................................................943
THE NAME OF A FORM..........................................................................................................................944
THE FORMS OF AN APPLICATION: THE TITLE BAR................................................................944
THE SYSTEM ICON.................................................................................................................................945
THE FORM'S CAPTION...........................................................................................................................947
THE SYSTEM BUTTONS..........................................................................................................................948
THE FORMS OF AN APPLICATION: THE FORM'S POSITION.................................................951
THE FORM'S LOCATION.........................................................................................................................951
THE STARTUP POSITION OF A FORM.....................................................................................................954
THE WINDOW STATE OF A FORM..........................................................................................................955
THE FORM'S TASKBAR PRESENCE.........................................................................................................956
THE FORMS OF AN APPLICATION: THE FORM'S MEASURES...............................................957
THE FORM'S SIZE...................................................................................................................................957
THE FORM BORDERS.............................................................................................................................960
THE FORMS OF AN APPLICATION: THE CLIENT AREA OF A FORM..................................962

C# 3.0 Practical Learning II 15


INTRODUCTION......................................................................................................................................962
THE BACKGROUND COLOR OF A FORM................................................................................................963
THE FORMS OF AN APPLICATION: THE BACKGROUND IMAGE OF A FORM.................965
INTRODUCTION......................................................................................................................................965
BACKGROUND IMAGE OPTIONS.............................................................................................................966
FORM CREATION...................................................................................................................................971
FORM ACTIVATION................................................................................................................................972
FORM DEACTIVATION...........................................................................................................................972
FORM CLOSURE.....................................................................................................................................972
DIALOG BOXES.....................................................................................................................................973
DESCRIPTION.........................................................................................................................................973
DIALOG BOX CREATION........................................................................................................................975
CHARACTERISTICS OF DIALOG BOXES......................................................................................976
THE BORDER STYLE OF A DIALOG BOX...............................................................................................976
THE MINIMIZE AND MAXIMIZE BOXES.................................................................................................976
CLOSING A DIALOG BOX.......................................................................................................................978
ACCEPTING AN ACTION.........................................................................................................................978
CANCELLING AN ACTION......................................................................................................................979
THE HELP BUTTON................................................................................................................................980
MODAL AND MODELESS DIALOG BOXES...................................................................................981
MODAL DIALOG BOXES........................................................................................................................981
MODELESS DIALOG BOXES...................................................................................................................982
AN APPLICATION WITH VARIOUS FORMS OR DIALOG BOXES..............................................................984
MESSAGE BOXES.................................................................................................................................986
INTRODUCTION......................................................................................................................................987
THE RETURN VALUE OF A MESSAGE BOX............................................................................................987
THE MESSAGE OF A MESSAGE BOX......................................................................................................988
THE CAPTION OF A MESSAGE BOX.......................................................................................................988
THE BUTTONS OF A MESSAGE BOX......................................................................................................989
THE ICON OF A MESSAGE BOX.............................................................................................................990
THE DEFAULT BUTTON OF A MESSAGE BOX........................................................................................991
THE CODE EDITOR..............................................................................................................................993
INTRODUCTION......................................................................................................................................993
THE TABS BAR......................................................................................................................................995
THE TYPES COMBO BOX.......................................................................................................................997
THE MEMBERS COMBO BOX.................................................................................................................997
CODE COLORS.......................................................................................................................................999
REGIONS................................................................................................................................................999
METHODS AND EVENTS OF WINDOWS CONTROLS...............................................................1002
INTRODUCTION....................................................................................................................................1002
CONTROL'S CONSTRUCTION AND DESTRUCTION................................................................................1002
CONTROL'S VISIBILITY........................................................................................................................1004
CONTROL'S FOCUS...............................................................................................................................1005
THE Z-ORDER OF CONTROLS..............................................................................................................1006
CREATING NEW METHODS..................................................................................................................1007
INTRODUCTION....................................................................................................................................1008
MICROSOFT VISUAL BASIC FUNCTIONS..............................................................................................1008
USING A LIBRARY...............................................................................................................................1008
USING A VISUAL C++/CLI LIBRARY..................................................................................................1009
USING THE WIN32 LIBRARY...............................................................................................................1009
A REVIEW OF DELEGATES.............................................................................................................1010
INTRODUCTION....................................................................................................................................1010

C# 3.0 Practical Learning II 16


DECLARING A DELEGATE....................................................................................................................1010
DELEGATES AND CLASSES..................................................................................................................1012
DELEGATES COMPOSITIONS................................................................................................................1014
A DELEGATE THAT TAKES ONE OF MORE ARGUMENTS....................................................................1014
A DELEGATE PASSED AS ARGUMENT.................................................................................................1015
APPLICATION ONLINE HELP.........................................................................................................1017
INTRODUCTION....................................................................................................................................1017
STATUS BAR MESSAGES......................................................................................................................1022
TOOL TIPS............................................................................................................................................1025
ONLINE HELP......................................................................................................................................1027
INTRODUCTION....................................................................................................................................1027
THE HELP PROVIDER...........................................................................................................................1032
INTRODUCTION TO HTML HELP.........................................................................................................1035
HTML HELP AND VISUAL STUDIO 2005APPLICATIONS.....................................................................1057
THE TOOLBOX....................................................................................................................................1060
INTRODUCTION....................................................................................................................................1060
THE TOOLBOX AND ADDITIONAL CONTROLS.....................................................................................1061
THE SECTIONS OF THE TOOLBOX........................................................................................................1063
THE LAYOUT OF A CATEGORY............................................................................................................1064
ARRANGEMENT OF ITEMS IN THE TOOLBOX.......................................................................................1066
INTRODUCTION TO APPLICATION DESIGN.............................................................................1066
INTRODUCTION....................................................................................................................................1067
COPYING A CONTROL..........................................................................................................................1069
DYNAMIC CONTROL CREATION..................................................................................................1069
INTRODUCTION....................................................................................................................................1069
INITIALIZING THE COMPONENTS.........................................................................................................1071
USING A PARTIAL CLASS....................................................................................................................1072
COMPONENTS TRACKING ON AN APPLICATION...................................................................................1073
CONTROL DERIVATION........................................................................................................................1074
CONTROL SELECTION.....................................................................................................................1075
INTRODUCTION....................................................................................................................................1075
SINGLE CONTROL SELECTION.............................................................................................................1076
MULTIPLE CONTROL SELECTION.........................................................................................................1076
CONTROL DELETION............................................................................................................................1077
THE PROPERTIES WINDOW...........................................................................................................1077
INTRODUCTION....................................................................................................................................1077
DESCRIPTION.......................................................................................................................................1078
ACCESSING THE PROPERTIES OF ONE OR MORE CONTROLS...............................................................1079
PROPERTIES CATEGORIES............................................................................................................1081
INTRODUCTION....................................................................................................................................1081
EMPTY FIELDS.....................................................................................................................................1082
TEXT FIELDS........................................................................................................................................1083
NUMERIC FIELDS.................................................................................................................................1084
DATE-BASED FIELDS...........................................................................................................................1085
EXPANDABLE FIELDS..........................................................................................................................1086
BOOLEAN FIELDS.................................................................................................................................1088
ACTION FIELDS....................................................................................................................................1088
LIST-BASED FIELDS.............................................................................................................................1089
Area-Selection Fields..........................................................................................................................1090

C# 3.0 Practical Learning II 17


C# 3.0 Practical Learning II 18
Querying a List
 

The Language Integrated Query


 

Introduction to Querying

When using for or foreach loops on a list, you get the value or a range of
values inside of the loop. Once you exit the loop, the operation ends and you
cannot access the value(s) that was(were) isolated. If you want to get the
isolated value or an isolated list of values again, you would have to perform
the operation (create the loop), again. In some cases, you may want to
prepare and get one value, a few values, or a range of values for later use, or
to use over and over again. To do this, you would create a value or a list of
values and store that list in a variable, outside of any loop, then use the value
or the list of values when needed. As applied to the for or the foreach loop,
to perform this operation, you use a conditional statement that would
examine the list, look for the value(s), get that value or those values that
respond(s) to the condition. Any value(s) that respond(s) to the condition
is(are) then stored in the new list. This technique of examining an array is
referred to as querying.

  

Introduction to LINQ

To support the ability to query a list, you can use the Language Integrated
Query, abbreviated LINQ. To use LINQ in your application, you must include
the System.Core.dll assembly in your program. If you started your
application as an empty project:

 On the main menu, you can click Project -> Add Reference...

 In the Solution Explorer, you can right-click the name of the project and
click Add Reference...

 In the Class View, you can right-click the name of the project and click
Add Reference...

In the .NET tab of the Add Reference dialog box, you can click System.Core

C# 3.0 Practical Learning II 19


Then click OK. You must then use the System.Linq namespace in your code
or you should include the using System.Linq; line in your list of
namespaces.

If you create an application by selecting the Console Application option from


the New Project dialog box, the studio would add the necessary assembly to
your project and the necessary namespace to your code file.

Selecting the Values

To query a list, you write a statement using words and operators of the LINQ.

If you have already used another query language, such as SQL, you
may be wondering about LINQ's case-sensitivity. Here is the difference.
Because the LINQ statements are written directly in the same sections
with the langue of your code, LINQ's case-sensitivity depends on that
language. For example, if you write your LINQ statement in a C#
application as we will do here or in a C++ application where the
language is case-sensitive, the LINQ's statement is case-sensitive and
must be in lowercase. If you write the statement in a case-insensitive
language such as Visual Basic or Pascal (such as CodeGear Delphi), you
can write the statement with the case of your choice.

The most fundamental operation you can perform on LINQ consists of


creating, also referred to as selecting, a list of values, from an existing list
such as an array. The basic formula to use is:

C# 3.0 Practical Learning II 20


var SubListName = from ValueHolder in List select ValueHolder;

The var keyword, the assignment operator "=", the from keyword, the in
keyword, the select keyword, and the semicolon are required.

The SubListName is a name of a new variable that will hold the list of values
produced by this operation.

The ValueHolder is the name of a variable that will be used to identify each
resulting member of this operation. This variable will be equivalent to getting
each member of the array that responds to a condition.

The List factor represents the name of the variable that you would have
created already. The List can be an array. Here is an example:
using System;
using System.Linq;

public class Exercise


{
static int Main(string[] args)
{
var Numbers = new double[] { 12.44, 525.38, 6.28,
2448.32, 632.04 };

var Number = from n in Numbers select n;

foreach(var member in Number)


Console.WriteLine("Number: {0}", member);

return 0;
}
}

This would produce:


Number: 12.44
Number: 525.38
Number: 6.28
Number: 2448.32
Number: 632.04
Press any key to continue . . .

To make the code easier to read, you can spread the select statement to
various lines. Here is an example:
using System;
using System.Linq;

public class Exercise


{
static int Main(string[] args)
{
var Numbers = new double[] { 12.44, 525.38, 6.28,
2448.32, 632.04 };

C# 3.0 Practical Learning II 21


var Number = from n
in Numbers
select n;

foreach(var member in Number)


Console.WriteLine("Number: {0}", member);

return 0;
}
}

Using a Collection-Based Variable

We mentioned that the List factor of our formula could be an array. It can
also be a collection-based variable; that is, a variable created from a
collection-based class. The collection class you use must implement the
IEnumerable generic interface. If you want, you can create your own class
that implements this interface but the .NET Framework provides a complete
set of classes that should suit every need. One of the built-in generic classes
of the .NET Framework is called List and you can easily use it to create a list
of values. Here is an example:
using System;
using System.Collections.Generic;

public class Exercise


{
static int Main(string[] args)
{
var Numbers = new List<double>();

Numbers.Add(12.44);
Numbers.Add(525.38);
Numbers.Add(6.28);
Numbers.Add(2448.32);
Numbers.Add(632.04);

return 0;
}
}

After creating the collection, you can use the same LINQ formula we saw for
an array. Here is an example:
using System;
using System.Linq;
using System.Collections.Generic;

public class Exercise


{
static int Main(string[] args)
{
var Numbers = new List<double>();

C# 3.0 Practical Learning II 22


Numbers.Add(12.44);
Numbers.Add(525.38);
Numbers.Add(6.28);
Numbers.Add(2448.32);
Numbers.Add(632.04);

var Number = from n


in Numbers
select n;

foreach (var member in Number)


Console.WriteLine("Number: {0}", member);

return 0;
}
}

This would produce the same result as seen earlier. Notice that, as always,
the var keyword does not indicate the type of variable it is dealing with.

Using a Criterion to Create a Sub-List

As you can see, simply using a select statement as done above produces
the same list of values in the array. A criterion is a condition applied to a set
of values to find out which one(s) respond(s) to the condition or validate the
condition. When applied to an array, a criterion examines each member of the
array, finds out what member responds to it, if so, adds that member to the
from list.

To apply a criterion, you create Boolean operation between the in statement


and the select statement. This criterion is actually formulated using the
where operator. The formula to use is:

var SubListName = from ValueHolder in List where Condition


select ValueHolder;

In the new section, the where keyword is required. The Condition is


formulated using the logical operators we studied in Lesson 9. It can be in
the form of:

 ValueHolder == SomeValue: If ValueHolder is the same as SomeValue,


the list member that is being examined is valid

 ValueHolder < SomeValue: If ValueHolder is less than SomeValue, the


list member that is being examined is valid

 ValueHolder <= SomeValue: If ValueHolder is the same as, or lower


than, SomeValue, the list member that is being examined is valid

 ValueHolder > SomeValue: If ValueHolder is greater than SomeValue,


the list member that is being examined is valid

C# 3.0 Practical Learning II 23


 ValueHolder >= SomeValue: If ValueHolder is the same as, or greater
than, SomeValue, the list member that is being examined is valid

 ValueHolder != SomeValue: If ValueHolder is different from SomeValue,


the list member that is being examined is valid

 !(ValueHolder == SomeValue): If ValueHolder is different from


SomeValue, the list member that is being examined is valid
Remember that you must create the criterion as a Boolean operation. After
applying the select statement, you can then use it as you see fit. For
example, you can display its result(s) to the console. Here is an example:
using System;
using System.Linq;

public class Exercise


{
static int Main(string[] args)
{
var Numbers = new[] { 102, 44, 525, 38, 6, 28, 24481,
327, 632, 104 };

var Number = from n


in Numbers
where n == 327
select n;

foreach (var member in Number)


Console.WriteLine("Number: {0}", member);

return 0;
}
}

This would produce:


Number: 327
Press any key to continue . . .

Of course, the purpose of querying a list is to isolate one or more values. As


such, you can create an expression that checks a value and applies some
condition to it. For example, in this list of numbers, you may want to find out
whether it contains one or more numbers that are divisible by 5. This
operation can be carried by the % operator as in "number % 5"; but number
% 5 is pure algebra, not Boolean. Therefore, you must add a condition to
make it a valid Boolean expression. For example, you can find out if the
number % 5 operation is equal to 0. Here is an example:
using System;
using System.Linq;

public class Exercise


{

C# 3.0 Practical Learning II 24


static int Main(string[] args)
{
var Numbers = new[] { 102, 44, 525, 38, 6, 28, 24481,
327, 632, 104 };

var Number = from n


in Numbers
where n % 5 == 0
select n;

foreach (var member in Number)


Console.WriteLine("Number: {0}", member);

return 0;
}
}

This would produce:


Number: 525
Press any key to continue . . .

To make the statement easier to read and less confusing, you should make it
a habit to isolate the groups of statements in parentheses:
using System;
using System.Linq;

public class Exercise


{
static int Main(string[] args)
{
var Numbers = new[] { 102, 44, 525, 38, 6, 28, 24481,
327, 632, 104 };

var Number = from n


in Numbers
where (n % 5) == 0
select n;

foreach (var member in Number)


Console.WriteLine("Number: {0}", member);

return 0;
}
}

The above condition produced only one value because of the way the values
exist in our array. A querying operation can also produce more than one
value. Here is an example:
using System;
using System.Linq;

public class Exercise


{

C# 3.0 Practical Learning II 25


static int Main(string[] args)
{
var Numbers = new[] { 102, 44, 525, 38, 6, 28, 24481,
327, 632, 104 };

var Number = from n


in Numbers
where n % 2 == 0
select n;

foreach (var member in Number)


Console.WriteLine("Number: {0}", member);

return 0;
}
}

This would produce:


Number: 102
Number: 44
Number: 38
Number: 6
Number: 28
Number: 632
Number: 104
Press any key to continue . . .

Notice that the list includes only even numbers (those that are divisible by 2).

Operations on Queries
 

Using Logical Conjunctions and  Disjunctions

In Lesson 10, we saw that you could use logical conjunctions and
disjunctions to combine two or more Boolean expressions. These also are
available in LINQ. To do this, use the where statement to create the
expression as you see fit. Here is an expression that uses a logical disjunction
(&&) operation:
using System;
using System.Linq;

public class Exercise


{
static int Main(string[] args)
{
var Numbers = new[] { 102, 44, 525, 38, 6, 28, 24481,
327, 632, 104 };

var Number = from n

C# 3.0 Practical Learning II 26


in Numbers
where n % 2 == 0 && n <= 100
select n;

foreach (var member in Number)


Console.WriteLine("Number: {0}", member);

return 0;
}
}

This would produce:


Number: 44
Number: 38
Number: 6
Number: 28
Press any key to continue . . .

Once again, remember that the use of parentheses makes it easier to read
the code and better understand it:
using System;
using System.Linq;

public class Exercise


{
static int Main(string[] args)
{
var Numbers = new[] { 102, 44, 525, 38, 6, 28, 24481,
327, 632, 104 };

var Number = from n


in Numbers
where (n % 2 == 0) && (n <= 100)
select n;

foreach (var member in Number)


Console.WriteLine("Number: {0}", member);

return 0;
}
}

Or better yet:
using System;
using System.Linq;

public class Exercise


{
static int Main(string[] args)
{
var Numbers = new[] { 102, 44, 525, 38, 6, 28, 24481,
327, 632, 104 };

C# 3.0 Practical Learning II 27


var Number = from n
in Numbers
where ((n % 2) == 0) && (n <= 100)
select n;

foreach (var member in Number)


Console.WriteLine("Number: {0}", member);

return 0;
}
}

Arranging the List

When you create a list, you add the items in any order of your choice. For
example, if you register the students of a school, you enter their information
as it becomes available. In the same way, when you create a select
statement, the items are added to its list in the order they appear in the main
list. When treating the new list or when displaying it to the user, you may
want to arrange it in alphabetical, numerical, or in chronological order. To
support this operation, the LINQ provides the orderdy operator. To apply it,
write the operator before the select operation followed by the from list. Here
is an example:
using System;
using System.Linq;

public class Program


{
static int Main(string[] args)
{
var Numbers = new[] { 102, 44, 525, 38, 6, 28, 24481,
327, 632, 104 };

var Number = from n


in Numbers
orderby n
select n;

foreach (var member in Number)


Console.WriteLine("Number: {0}", member);
return 0;
}
}

This would produce:


Number: 6
Number: 28
Number: 38
Number: 44
Number: 102
Number: 104
Number: 327

C# 3.0 Practical Learning II 28


Number: 525
Number: 632
Number: 24481
Press any key to continue . . .

If you apply the orderby operator simply followed by a variable, the list is
ordered alphabetically or numerically depending on the types of values in the
list. This is referred to as ascending. To re-enforce this, you can follow the
variable with the ascending keyword. Here is an example:
using System;
using System.Linq;

public class Program


{
static int Main(string[] args)
{
var Numbers = new[] { 102, 44, 525, 38, 6, 28, 24481,
327, 632, 104 };

var Number = from n


in Numbers
orderby n ascending
select n;

foreach (var member in Number)


Console.WriteLine("Number: {0}", member);
return 0;
}
}

To arrange the list in reverse order, you can follow the variable name with the
descending keyword. Here is an example:

using System;
using System.Linq;

public class Program


{
static int Main(string[] args)
{
var Numbers = new[] { 102, 44, 525, 38, 6, 28, 24481,
327, 632, 104 };

var Number = from n


in Numbers
orderby n descending
select n;

foreach (var member in Number)


Console.WriteLine("Number: {0}", member);
return 0;
}
}

C# 3.0 Practical Learning II 29


This would produce:
Number: 24481
Number: 632
Number: 525
Number: 327
Number: 104
Number: 102
Number: 44
Number: 38
Number: 28
Number: 6
Press any key to continue . . .

You can apply a where condition to the statement to select just a few values.
For example, to get a list of odd numbers arranged in numerical order, you
would write the statement as follows:
using System;
using System.Linq;

public class Program


{
static int Main(string[] args)
{
var Numbers = new[] { 102, 44, 525, 38, 6, 28, 24481,
327, 632, 104 };

var Number = from n


in Numbers
where n % 2 != 0
orderby n ascending
select n;

foreach (var member in Number)


Console.WriteLine("Number: {0}", member);
return 0;
}
}

Influencing a LINQ Statement


 

Using the Primitive Types

From what we have learned so far, the type of list produced by a LINQ
statement is primarily based on one of the data types we reviewed in Lesson
2 and in Lesson 3 (integers, double-precision numbers, strings, and date/time
values). In Lesson 17, we saw that the integer and numeric types are in fact
structures of the .NET Framework. As such, they are equipped with properties
and methods. In your LINQ statement, you can explore the characteristics of
those data types as you see fit.

C# 3.0 Practical Learning II 30


Using the String Class

If you create a string-based collection, you can use the properties and
methods of the String class to refine the list produced by your LINQ
statement. To do this, in the list produced by the where statement, you can
access any of the properties or you can call any desired method of the String
class using the period operator. For example, to get a list of names that start
with a certain letter, you can call the StartsWith() method as follows:
using System;
using System.Linq;

public class Program


{
static int Main(string[] args)
{
var Name = new[]
{
"Hermine", "Patrick", "Hank", "Bertine",
"Julius", "Thomas", "Jeannette", "Patricia",
"Henriette", "Raul", "David", "Paulette" };

var Names = from n


in Name
where n.StartsWith("P")
// orderby n ascending
select n;

foreach (var member in Names)


Console.WriteLine("Name: {0}", member);
return 0;
}
}

Or to get a list of names that end with a certain sub-string, you would call the
String.EndsWith() method. Here is an example:

using System;
using System.Linq;

public class Program


{
static int Main(string[] args)
{
var Name = new[]
{
"Hermine", "Patrick", "Hank", "Bertine",
"Julius", "Thomas", "Jeannette", "Patricia",
"Henriette", "Raul", "David", "Paulette" };

var Names = from n


in Name
where n.EndsWith("ette")
// orderby n ascending

C# 3.0 Practical Learning II 31


select n;

foreach (var member in Names)


Console.WriteLine("Name: {0}", member);
return 0;
}
}

In the same ways, to create a list of names that contain a certain sub-string,
you can call the String.Contains() method as follows:
using System;
using System.Linq;

public class Program


{
static int Main(string[] args)
{
var Name = new[]
{
"Hermine", "Patrick", "Hank", "Bertine",
"Julius", "Thomas", "Jeannette", "Patricia",
"Henriette", "Raul", "David", "Paulette" };

var Names = from n


in Name
where n.Contains("au")
// orderby n ascending
select n;

foreach (var member in Names)


Console.WriteLine("Name: {0}", member);
return 0;
}
}

LINQ and Classes


 

Introduction

To create more effective LINQ statements, you can use many of the features
of the C# language we have studied in previous lessons. For example, instead
of using one of the primitive types to create your list as we have done so far,
you may want to use your own class. You can start by creating the class
normally as you see fit. Here is an example:
public class Person
{
public string FirstName;
public string LastName;
public char Gender;

C# 3.0 Practical Learning II 32


public Person(string First, string Last, char Sex)
{
FirstName = First;
LastName = Last;
Gender = Sex;
}
}

Obviously before considering the class in your LINQ statement, you should
first create a collection variable that would hold its values. You can create the
list as an array. Once the list is ready, when formulating your LINQ
statement, use the from variable to access a member of the class using the
period operator. Here is an example:
using System;
using System.Linq;

public class Person


{
public string FirstName;
public string LastName;
public char Gender;

public Person(string First, string Last, char Sex)


{
FirstName = First;
LastName = Last;
Gender = Sex;
}
}

public class Program


{
static int Main(string[] args)
{
var People = new Person[]
{
new Person("Paulette", "Cranston", 'F'),
new Person("Harry", "Kumar", 'M'),
new Person("Jules", "Davidson", 'M'),
new Person("Leslie", "Harrington", 'U'),
new Person("Ernest", "Colson", 'M'),
new Person("Patricia", "Katts", 'F'),
new Person("Patrice", "Abanda", 'U'),
new Person("Frank", "Thomasson", 'M')
};

var Persons = from Pers


in People
select Pers.LastName;

foreach (var Individual in Persons)


Console.WriteLine("Person Name: {0}", Individual);
return 0;
}

C# 3.0 Practical Learning II 33


}

This would produce:


Person Name: Cranston
Person Name: Kumar
Person Name: Davidson
Person Name: Harrington
Person Name: Colson
Person Name: Katts
Person Name: Abanda
Person Name: Thomasson
Press any key to continue . . .

In the same way, you can use any of the regular C# operators to produce
any result of your choice. For example, when studying strings, we saw that
you could use the + operator to combine strings. Here is an example:
using System;
using System.Linq;

public class Person


{
public string FirstName;
public string LastName;
public char Gender;

public Person(string First, string Last, char Sex)


{
FirstName = First;
LastName = Last;
Gender = Sex;
}
}

public class Program


{
static int Main(string[] args)
{
var People = new Person[]
{
new Person("Paulette", "Cranston", 'F'),
new Person("Harry", "Kumar", 'M'),
new Person("Jules", "Davidson", 'M'),
new Person("Leslie", "Harrington", 'U'),
new Person("Ernest", "Colson", 'M'),
new Person("Patricia", "Katts", 'F'),
new Person("Patrice", "Abanda", 'U'),
new Person("Frank", "Thomasson", 'M')
};

var Persons = from Pers


in People
select Pers.LastName + ", " +
Pers.FirstName;

C# 3.0 Practical Learning II 34


foreach (var Individual in Persons)
Console.WriteLine("Person Name: {0}", Individual);
return 0;
}
}

This would produce:


Person Name: Cranston, Paulette
Person Name: Kumar, Harry
Person Name: Davidson, Jules
Person Name: Harrington, Leslie
Person Name: Colson, Ernest
Person Name: Katts, Patricia
Person Name: Abanda, Patrice
Person Name: Thomasson, Frank
Press any key to continue . . .

Remember that the essence of querying a list is to create a list of particular


data based on a criterion, which is done by applying a where condition. Here
is an example:
public class Program
{
static int Main(string[] args)
{
var People = new Person[]
{
new Person("Paulette", "Cranston", 'F'),
new Person("Harry", "Kumar", 'M'),
new Person("Jules", "Davidson", 'M'),
new Person("Leslie", "Harrington", 'U'),
new Person("Ernest", "Colson", 'M'),
new Person("Patricia", "Katts", 'F'),
new Person("Patrice", "Abanda", 'U'),
new Person("Frank", "Thomasson", 'M')
};

var Persons = from Pers


in People
where Pers.Gender == 'F'
select Pers.LastName + ", " +
Pers.FirstName;

foreach (var Individual in Persons)


Console.WriteLine("Person Name: {0}", Individual);
return 0;
}
}

This would produce:


Person Name: Cranston, Paulette
Person Name: Katts, Patricia
Press any key to continue . . .

C# 3.0 Practical Learning II 35


To perform a more particular operation on a class, you can create a method
in it and then call that method in your LINQ statement. This means that, just
as you can access a field or a property of the class, you can access any of its
internal or public methods. Here is an example:
using System;
using System.Linq;

public class Person


{
public string FirstName;
public string LastName;
public char Gender;

public Person(string First, string Last, char Sex)


{
FirstName = First;
LastName = Last;
Gender = Sex;
}

internal string GetFullName()


{
return LastName + ", " + FirstName;
}
}

public class Program


{
static int Main(string[] args)
{
var People = new Person[]
{
new Person("Paulette", "Cranston", 'F'),
new Person("Harry", "Kumar", 'M'),
new Person("Jules", "Davidson", 'M'),
new Person("Leslie", "Harrington", 'U'),
new Person("Ernest", "Colson", 'M'),
new Person("Patricia", "Katts", 'F'),
new Person("Patrice", "Abanda", 'U'),
new Person("Frank", "Thomasson", 'M')
};

var Persons = from Pers


in People
where Pers.Gender == 'M'
select Pers.GetFullName();

foreach (var Individual in Persons)


Console.WriteLine("Person Name: {0}", Individual);
return 0;
}
}

This would produce:

C# 3.0 Practical Learning II 36


Person Name: Kumar, Harry
Person Name: Davidson, Jules
Person Name: Colson, Ernest
Person Name: Thomasson, Frank
Press any key to continue . . .

Using Built-In Classes

There are two types of built-in classes you can use in your application when it
comes to LINQ. You can use any of the non-generic collection classes to
create a list of values. The other category is the generic collection classes.

LINQ Operators
 

Letting a Sub-List

We saw that you can get the result of a LINQ statement from the select
section. In reality, the select statement simply indicates that the result is
ready and it hands it to the other parts of the program. Instead of getting the
result directly from the select statement, you can first store it in a local LINQ
variable. This allows you to treat the result as a variable that you can then
manipulate before getting the final result.

To create a local variable in the LINQ statement, you can use the let
operator. You must use it before the select statement to hold the result. Here
is an example:
public class Program
{
static int Main(string[] args)
{
var Persons = from Pers
in People
let FullName = Pers.LastName + ", " +
Pers.FirstName
select FullName;

foreach (var Individual in Persons)


Console.WriteLine("Person Name: {0}", Individual);
return 0;
}
}

If you need a where condition but your let variable would be used only to
hold the final result, you can create that variable after the where statement.
Here is an example:
public class Program
{

C# 3.0 Practical Learning II 37


static int Main(string[] args)
{
var Persons = from Pers
in People
where Pers.Gender == 'U'
let FullName = Pers.LastName + ", " +
Pers.FirstName
select FullName;

foreach (var Individual in Persons)


Console.WriteLine("Person Name: {0}", Individual);
return 0;
}
}

In this case, you can create the let variable before the where statement and
you would get the same result:
using System;
using System.Linq;

public class Person


{
public string FirstName;
public string LastName;
public char Gender;

public Person(string First, string Last, char Sex)


{
FirstName = First;
LastName = Last;
Gender = Sex;
}
}

public class Program


{
static int Main(string[] args)
{
var People = new Person[]
{
new Person("Paulette", "Cranston", 'F'),
new Person("Harry", "Kumar", 'M'),
new Person("Jules", "Davidson", 'M'),
new Person("Leslie", "Harrington", 'U'),
new Person("Ernest", "Colson", 'M'),
new Person("Patricia", "Katts", 'F'),
new Person("Patrice", "Abanda", 'U'),
new Person("Frank", "Thomasson", 'M')
};

var Persons = from Pers


in People
let FullName = Pers.LastName + ", " +
Pers.FirstName
where Pers.Gender == 'U'

C# 3.0 Practical Learning II 38


select FullName;

foreach (var Individual in Persons)


Console.WriteLine("Person Name: {0}", Individual);
return 0;
}
}

This would produce:


Person Name: Harrington, Leslie
Person Name: Abanda, Patrice
Press any key to continue . . .

Creating a new List

To get the final result of a query, you may want to combine a few fields or
properties of each member of the result. For example, as we have seen so
far, you may want to combine the last and the first name of each result to
create a full name. Besides, or instead of, the let operator, you can use the
new operator to create such a combination.

To use the new operator, after the select keyword, type new followed by an
opening and a closing curly brackets. Inside the brackets, create an
expression as you see fit and assign it to a local variable in the curly brackets.
When accessing the result in your foreach loop, apply the period operator on
the foreach variable to access the new local variable. Here is an example:
public class Person
{
public string FirstName;
public string LastName;
public char Gender;

public Person(string First, string Last, char Sex)


{
FirstName = First;
LastName = Last;
Gender = Sex;
}
}

public class Program


{
static int Main(string[] args)
{
var People = new Person[]
{
new Person("Paulette", "Cranston", 'F'),
new Person("Harry", "Kumar", 'M'),
new Person("Jules", "Davidson", 'M'),

C# 3.0 Practical Learning II 39


new Person("Leslie", "Harrington", 'U'),
new Person("Ernest", "Colson", 'M'),
new Person("Patricia", "Katts", 'F'),
new Person("Patrice", "Abanda", 'U'),
new Person("Frank", "Thomasson", 'M')
};

var Persons = from Pers


in People
select new {FullName=Pers.LastName+",
"+Pers.FirstName };

foreach (var Individual in Persons)


Console.WriteLine("Person Name: {0}",
Individual.FullName);
return 0;
}
}

To make the statement easier to read, you can span it on various lines:
public class Program
{
static int Main(string[] args)
{
var Persons = from Pers
in People
select new
{
FullName = Pers.LastName +
", " +
Pers.FirstName
};

foreach (var Individual in Persons)


Console.WriteLine("Person Name: {0}",
Individual.FullName);
return 0;
}
}

C# 3.0 Practical Learning II 40


Exploring the LINQ
 

The IEnumerable Generic Interface


 

Introduction

In our introduction to LINQ, we saw how to create a LINQ statement by


declaring a variable using the var keyword. Here is an example:

using System;

using System.Linq;

public class Program


{
static int Main(string[] args)
{
var People = new string[]
{
"Paulette Cranston",
"Harry Kumar",
"Jules Davidson",
"Leslie Harrington",
"Ernest Colson",
"Patricia Katts",
"Patrice Abanda",
"Frank Thomasson"
};

var Persons = from Pers


in People
select Pers;

foreach (var Individual in Persons)


Console.WriteLine("Person: {0}",
Individual);
return 0;
}
}

This would produce:


Person: Paulette Cranston
Person: Harry Kumar
Person: Jules Davidson

C# 3.0 Practical Learning II 41


Person: Leslie Harrington
Person: Ernest Colson
Person: Patricia Katts
Person: Patrice Abanda
Person: Frank Thomasson
Press any key to continue . . .

From what we have learned so far, the only thing we know from this code is
that it gives us a list and we can display the values of this list to the console.
At times, we may want to get more information about some characteristics of
the result, not simply its values.

To assist you with exploring the characteristics of a LINQ statement, the .NET
Framework provides the IEnumerable interface.

Using IEnumerable

In all of the statements we have created/written so far, we used the var


keyword, which allowed us to let the compiler figure out what type of value
the statement would produce. In reality, a LINQ statement is an object of
type IEnumerable. The IEnumerable object used in LINQ is an interface
defined in the System.Collections.Generic namespace defined in the
mscorlib.dll assembly. This also means that you want to use it, you should
include the System.Collections.Generic namespace in your code file.

Since a LINQ statement produces a list of type IEnumerable, instead of the


var keyword, you can declare the statement using that. Inside the <>
operator, enter the type of list that the collection variable contains. Here is an
example:
using System;
using System.Linq;
using System.Collections.Generic;

public class Program


{
static int Main(string[] args)
{
var People = new string[]
{
"Paulette Cranston",
"Harry Kumar",
"Jules Davidson",
"Leslie Harrington",
"Ernest Colson",
"Patricia Katts",
"Patrice Abanda",
"Frank Thomasson"
};

IEnumerable<string> Persons =
from Pers

C# 3.0 Practical Learning II 42


in People
select Pers;

foreach (var Individual in Persons)


Console.WriteLine("Person: {0}", Individual);
return 0;
}
}

This statement is the same as the previous except that the var keyword has
been replaced with IEnumerable<string> and it will produce the same
result we had earlier.

The Characteristics of IEnumerable

As mentioned already, when you create a LINQ statement, it produces a list.


Although the list is of type IEnumerable, since this is only an interface, the
result relies on an actual class to provide its characteristics. The class that
gives you information about a result is called Enumerable.

The Enumerable class in defined in the System.Linq namespace that is part


of the System.Core.dll assembly. It is actually the Enumerable class that
implements the methods declared in the IEnumerable interface. Because the
Enumerable class is extremely big, we cannot review all of its methods. We
will use them as we move on and when a particular method becomes
necessary.

As mentioned already, a LINQ statement produces an Enumerable list. You


can then use that result to access a method of the class. For example, the
IEnumerable.Count() method is used to know the number of items in the
resulting list. You can access it from the resulting list. Here is an example:
using System;
using System.Linq;
using System.Collections.Generic;

public class Program


{
static int Main(string[] args)
{
var People = new string[]
{
"Paulette Cranston",
"Harry Kumar",
"Jules Davidson",
"Leslie Harrington",
"Ernest Colson",
"Patricia Katts",
"Patrice Abanda",
"Frank Thomasson"
};

C# 3.0 Practical Learning II 43


IEnumerable<string> Persons =
from Pers
in People
select Pers;
int Total = Persons.Count();

Console.Write("There are {0} people in the list and they


are: ", Total);
foreach (var Individual in Persons)
Console.Write("{0}, ", Individual);

Console.WriteLine();
return 0;
}
}

This would produce:


There are 8 people in the list and they are: Paulette Cranston,
Harry Kumar, Jul
es Davidson, Leslie Harrington, Ernest Colson, Patricia Katts,
Patrice Abanda, F
rank Thomasson,
Press any key to continue . . .

Remember that you can still use the var keyword to declare the variable that
would hold the resulting list.

Since we have determined that the LINQ statement produces an Enumerable


object, if you don't need the list itself, you can declare a variable that is the
type returned by a method, put the statement in parentheses, and then
access the method outside the closing parenthesis using the period operator.
Here is an example:
using System;
using System.Linq;
using System.Collections.Generic;

public class Program


{
static int Main(string[] args)
{
var People = new string[]
{
"Paulette Cranston",
"Harry Kumar",
"Jules Davidson",
"Leslie Harrington",
"Ernest Colson",
"Patricia Katts",
"Patrice Abanda",
"Frank Thomasson"
};

int Total = (from Pers

C# 3.0 Practical Learning II 44


in People
select Pers).Count();

Console.Write("There are {0} people in the list.",


Total);

Console.WriteLine();
return 0;
}
}
There are 8 people in the list.
Press any key to continue . . .

Remember that the IEnumerable.Count() method returns the number of


items in the result of the LINQ statement, not the number of items in the
original list. The following examples illustrate it:
using System;
using System.Linq;

public class Person


{
public string FirstName;
public string LastName;
public char Gender;

public Person(string First, string Last, char Sex)


{
FirstName = First;
LastName = Last;
Gender = Sex;
}
}

public class Program


{
static int Main(string[] args)
{
var People = new Person[]
{
new Person("Paulette", "Cranston", 'F'),
new Person("Harry", "Kumar", 'M'),
new Person("Jules", "Davidson", 'M'),
new Person("Leslie", "Harrington", 'U'),
new Person("Ernest", "Colson", 'M'),
new Person("Patricia", "Katts", 'F'),
new Person("Patrice", "Abanda", 'U'),
new Person("Frank", "Thomasson", 'M')
};

var AllPeople = from Pers


in People
select Pers;
int Men = (from Males
in AllPeople
where Males.Gender == 'M'

C# 3.0 Practical Learning II 45


select Males).Count();
int Women = (from Females
in AllPeople
where ((Females.Gender != 'M') &&
(Females.Gender != 'U'))
select Females).Count();

Console.Write("The original list contains {0} people and


they are: ",
AllPeople.Count());
foreach (var Individual in AllPeople)
Console.Write("{0}, ", Individual);

Console.WriteLine();
Console.WriteLine("This list contains {0} men and {1}
women.",
Men, Women);
return 0;
}
}

This would produce:


The original list contains 8 people and they are: Person,
Person, Person, Person
, Person, Person, Person, Person,
This list contains 4 men and 2 women.
Press any key to continue . . .

C# 3.0 Practical Learning II 46


Introduction to XML
 

The Extensible Markup Language


 

Overview of Files

Consider the following list:

Employee

First Hourly
Last Name Date Hired
Name Salary

Johnny Watts 10/05/1984 22.85

Patrick Garçon 7/22/2000 14.50

Ernest Simms 04/18/1996 18.05

Gertrude Monay 8/06/2002 26.35

In Lesson 33, we saw how to create and save such a list. Here is an example
of performing these operations:

using System;
using System.IO;
using System.Collections;
using System.Runtime.Serialization.Formatters.Binary;

[Serializable]
public sealed class Employee
{
public string FirstName;
public string LastName;
public DateTime DateHired;
public double HourlySalary;

C# 3.0 Practical Learning II 47


}

public static class Program


{
static int Main(string[] args)
{
ArrayList lstEmployees = new ArrayList();
Employee contractor = null;

contractor = new Employee();


contractor.FirstName = "Johnny";
contractor.LastName = "Watts";
contractor.DateHired = new DateTime(1984, 5, 10);
contractor.HourlySalary = 22.85;
lstEmployees.Add(contractor);

contractor = new Employee();


contractor.FirstName = "Patrick";
contractor.LastName = "Garçon";
contractor.DateHired = new DateTime(2000, 7, 24);
contractor.HourlySalary = 14.50;
lstEmployees.Add(contractor);

contractor = new Employee();


contractor.FirstName = "Ernest";
contractor.LastName = "Simms";
contractor.DateHired = new DateTime(1996, 4, 16);
contractor.HourlySalary = 18.05;
lstEmployees.Add(contractor);

contractor = new Employee();


contractor.FirstName = "Gertrude";
contractor.LastName = "Monay";
contractor.DateHired = new DateTime(2002, 3, 8);
contractor.HourlySalary = 26.35;
lstEmployees.Add(contractor);

FileStream fsEmployees = new FileStream("Employees.mpl",


FileMode.Create,

FileAccess.Write);
BinaryFormatter bfEmployees = new BinaryFormatter();
bfEmployees.Serialize(fsEmployees, lstEmployees);
fsEmployees.Close();

return 0;
}
}

When saving this file, we chose an extension (.mpl) at random. After saving
the values to a file, at one time, you may want to retrieve the values from
that list. Here is an example:
using System;
using System.IO;
using System.Collections;

C# 3.0 Practical Learning II 48


using System.Runtime.Serialization.Formatters.Binary;

[Serializable]
public sealed class Employee
{
public string FirstName;
public string LastName;
public DateTime DateHired;
public double HourlySalary;
}

public static class Program


{
static int Main(string[] args)
{
FileStream fsEmployees = new FileStream("Employees.mpl",
FileMode.Open,

FileAccess.Read);
BinaryFormatter bfEmployees = new BinaryFormatter();
ArrayList contractors =
(ArrayList)bfEmployees.Deserialize(fsEmployees);
fsEmployees.Close();

Console.WriteLine("======================================");
Console.WriteLine("==== Employees Records
===============");
foreach (Employee empl in contractors)
{

Console.WriteLine("--------------------------------------");
Console.WriteLine("Employee Name: {0}, {1}",
empl.LastName, empl.FirstName);
Console.WriteLine("Date Hired: {0:D}",
empl.DateHired);
Console.WriteLine("Hourly Salary: {0:C}",
empl.HourlySalary);
}

Console.WriteLine("======================================\n");

return 0;
}
}

This would produce:


======================================
==== Employees Records ===============
--------------------------------------
Employee Name: Watts, Johnny
Date Hired: Thursday, May 10, 1984
Hourly Salary: $22.85
--------------------------------------
Employee Name: Garçon, Patrick

C# 3.0 Practical Learning II 49


Date Hired: Monday, July 24, 2000
Hourly Salary: $14.50
--------------------------------------
Employee Name: Simms, Ernest
Date Hired: Tuesday, April 16, 1996
Hourly Salary: $18.05
--------------------------------------
Employee Name: Monay, Gertrude
Date Hired: Friday, March 08, 2002
Hourly Salary: $26.35
======================================

Press any key to continue . . .

When you create this type of file, you choose the programming environment
of your choice and save the file. You cannot open that file in just any
application. You must create and distribute the application to those who
want to be able to open a file created by your application. It could be useful
to create a type of file using any application of your choice and be able to
open that file using another type of application that you may not even know.

Introduction to XML

The Extensible Markup Language, or XML, is a technique of using a


document, such as a text file, to describe information and make that
information available to whatever and whoever can take advantage of it. The
description is done so the document can be created by one person or
company and used by another person or another company without having to
know who first created the document. This is because the document thus
created is not a program, it is not an application: it is just a text-based
document.

Because XML is very flexible, it can be used in regular Windows applications,


in databases, in web-based systems (Internet), in communication
applications, in computer networks, in scientific applications, etc. To make
sure that XML can be universally used without one person or group owning it,
it is standardized by the W3C (http://www.w3c.org) organization. XML is
released through an XML Recommendation document with a version.

In this ebook, we will learn or use XML through the .NET Framework classes.
The particularity is that these classes are highly structured to take care of all
facets of XML without compromising the standards. In fact, the .NET
Framework classes are highly conform to the W3C standards in all areas.

To create an XML file, in the document, you type units of code using normal
characters of the English language. The XML document is made of units called
entities. These entities are spread on various lines of the document as you
judge them necessary and as we will learn. XML has strict rules as to how the
contents of the document should or must be structured.

C# 3.0 Practical Learning II 50


After an XML document has been created and is available, in order to use it,
you need a program that can read, analyze, and interpret it. This program is
called a parser. The most popular parser used in Microsoft Windows
applications is MSXML, published by Microsoft.

Markup

A markup is an instruction that defines XML. The fundamental formula of a


markup is:
<tag>

The left angle bracket "<" and the right angle bracket ">" are required.
Inside of these symbols, you type a word or a group of words of your choice,
using regular characters of the English alphabet and sometimes non-readable
characters such as ?, !, or [. The combination of a left angle bracket "<", the
right angle bracket ">", and what is inside of these symbols is called a
markup. There are various types of markups we will learn.

The Document Type Declaration (DTD)

As mentioned above, XML is released as a version. Because there can be


various versions, the first line that can be processed in an XML file must
specify the version of XML you are using. At the time of this writing, the
widely supported version of the .NET Framework is 1.0. When creating an
XML file, you should (should in 1.0 but must in 1.1) specify what version your
file is conform with, especially if you are using a version higher than 1.0. For
this reason, an XML file should start (again, must, in 1.1), in the top section,
with a line known as an XML declaration. It starts with <?xml version=,
followed by the version you are using, assigned as a string, and followed by ?
>. An example of such a line is:

<?xml version="1.0"?>

By default, an XML file created using Visual Studio 2005 specifies the version
as 1.0. Under the XML declaration line, you can then create the necessary
tags of the XML file.

Encoding Declaration

As mentioned already, the tags are created using characters of the alphabet
and conform to the ISO standard. This is known as the encoding declaration.
For example, most of the characters used in the US English language are
known as ASCII. These characters use a combination of 7 bits to create a
symbol (because the computer can only recognize 8 bits, the last bit is left for
other uses). Such an encoding is specified as UTF-8. There are other
standards such as UTF-16 (for wide, 2-Byte, characters).

C# 3.0 Practical Learning II 51


To specify the encoding you are using, type encoding followed by the
encoding scheme you are using, which must be assigned as a string. The
encoding is specified in the first line. Here is an example:
<?xml version="1.0" encoding="utf-8"?>

Creating an XML File

Due to the high level of support of XML in the .NET Framework, there are
various ways you can create an XML file. The most common technique
consists of using a simple text editor. In Microsoft Windows, this would be
Notepad. An XML file is first of all a normal text-based document that has a
.xml extension. Therefore, however you create it, it must specify that
extension.

Many other applications allow creating an XML file or generating one from an
existing file. There are also commercial editors you can get or purchase to
create an XML file.

Practical Learning: Introducing XML

1. Start Microsoft Visual C# and create a Console Application named


CollegeParkAutoParts1

2. To save the application, on the Standard toolbar, click the Save All
button

3. Accept all defaults and click Save

Writing XML Code


 

Introduction to the Document Object Model

To implement XML, the .NET Framework provides the System.Xml


namespace. When you create an XML file, there are standard rules you
should (must) follow in order to have a valid document. The standards for an
XML file are defined by the W3C Document Object Model (DOM). To support
these standards, the System.Xml namespace provides the XmlDocument
class. This class allows you to create an XML document, to populate it with
the desired contents, and to perform many other related operations on the
contents of the file.

Writing XML Code Using XmlDocument

To create XML code using XmlDocument, this class has a method called
LoadXml(). Its syntax is:

C# 3.0 Practical Learning II 52


public virtual void LoadXml(string xml);

This method takes a string as argument. The XmlDocument.LoadXml()


method doesn't create an XML file, it only allows you to provide or create XML
code. The code can be created as argument. You can also first declare and
initialize a string variable with the XML code, then pass it as argument to
the XmlDocument.LoadXml() method.

Practical Learning: Creating an XML Document

1. To start with XML, change the Program.cs file as follows:


 
using System;
using System.Xml;

namespace CollegeParkAutoParts1
{
class Program
{
static int Main(string[] args)
{
XmlDocument docXML = new XmlDocument();

docXML.LoadXml("");
return 0;
}
}
}

2. Save the Program.cs file

Writing XML Code Using the Code Editor

In the next sections, we will see how to create an XML file with the Add New
Item dialog box. After creating the file and displaying it in the Code Editor,
you can start editing it. The Code Editor is equipped to assist you with various
options. Whenever you start typing, the editor would display one or more
options to you. Here is an example:

When different options are presented to you, you can press the arrow keys to
select an option and press Enter. You can also use the mouse to click an

C# 3.0 Practical Learning II 53


option. When typing other XML items as we will learn, the Code Editor is
equipped to work in concert with you.

Saving an XML File


 

Introduction

Probably the most common way to create an XML file in Microsoft Windows
consists of using Notepad or any other text editor. After opening the text
editor, you can enter the necessary lines of text. After creating the file, you
must save it. When saving it, you can include the name of the file in double-
quotes:

You can also first set the Save As Type combo box to All Files and then enter
the name of the file with the .xml extension.

Using the Wizard

To assist you with creating XML Files, Microsoft Visual C# includes an XML
File option in the Add New Item dialog box. After selecting this option, you

C# 3.0 Practical Learning II 54


can accept the suggested name of the file or replace it in the Name text box.
If you don't specify the extension, the wizard would add it for you.

Practical Learning: Creating the Root Tag

1. On the main menu, click Project -> Add New Item...

2. In the Templates list, click XML File

3. Set the Name to Parts


 

4. Click Add

Saving a DOM Object

If you call the XmlDocument.LoadXml() method, only the XML code is


created, not the file. To actually create the Windows file, you can call the
XmlDocument.Save() method. This method is provided in four versions. One
of the versions takes as argument a string value. The syntax of this method
is:
public virtual void Save(string filename);

The argument must be a valid filename and must include the .xml extension.
If you pass a string without backlashes, the file would be created in the same

C# 3.0 Practical Learning II 55


folder as the current project. If you want the file to be created somewhere
else (in a different directory), pass the whole path.

Opening an XML File


 

Introduction

Whether you created an XML file or someone else did, you can open it easily
to view its contents. The easiest way to open an XML file is to use a text
editor, such as Notepad. Because the Code Editor has a friendlier appearance
and it is available to you, it is a better candidate. To open an XML file, on the
main menu, you can click File -> Open File..., locate the file, and click Open.

An XML File in a Browser

After creating an XML file, one way you can use it is to display it in a grid-
based window such as a spreadsheet. Another way you can display an XML
file is in a browser. To do this, if you see the file in Windows Explorer or in My
Documents, you can double-click it. Here is an example:

C# 3.0 Practical Learning II 56


 

Using a Style Sheet to Display an XML File in a Browser

When an XML file is displayed in a browser, it appears in a format that could


be unclear. If you want the XML code to display as if it were HTML, you can
create a cascading style sheet that would format the tags and display the text
as you prefer. Here is an example: 
employee.css

EmplNumber
{
display: block;

C# 3.0 Practical Learning II 57


font-weight: bold;
font-size: 16pt;

color: white;
font-family: Garamond, Georgia, 'Times New Roman' ,
Serif;
background-color: #990000;
}
FirstName
{
font-size: 10pt;
font-family: Verdana, Tahoma, Arial, Sans-Serif;
background-color: white;
}
LastName
{
font-size: 10pt;
font-family: Verdana, Tahoma, Arial, Sans-Serif;
background-color: white;
}
HourlySalary
{
font-size: 10pt;
color: #ff0066;
font-family: Verdana, Tahoma, Arial, Sans-Serif;
background-color: white;
display: block;
}

Then, in the first line of the XML file, you can add a line such as the following:

<?xml:stylesheet href="employee.css" type="text/css" ?>

Programmatically Opening an XML File Using the DOM

At times, you will need to programmatically access an XML file. To support


this operation, the XmlDocument class provides the Load() method which is
available in various versions. One of the syntaxes used by this method is:
public virtual void Load(string filename);

This version takes as argument the name or path of the file. Here is an
example of calling it:
using System;
using System.Xml;

namespace VideoCollection1
{
class Program
{
static int Main(string[] args)
{

C# 3.0 Practical Learning II 58


XmlDocument xmlDoc = new XmlDocument();

xmlDoc.Load("Videos.xml");

return 0;
}
}
}

In this case, the compiler would look for the file in the (Release) folder of the
current application. You can also provide a complete path to the file. Either
way, if the compiler doesn't find the file, it would throw a
FileNotFoundException exception. For this reason, it is cautious to first
check that the file exists before opening it. This can be done as follows:
using System;
using System.IO;
using System.Xml;

namespace VideoCollection1
{
class Program
{
static int Main(string[] args)
{
XmlDocument xmlDoc = new XmlDocument();
string strFilename = "Videos123.xml";

if (File.Exists(strFilename))
xmlDoc.Load(strFilename);
else
Console.WriteLine("The file {0} could not be
located",
strFilename);

return 0;
}
}
}

An alternative is to handle the exception yourself.

You can also use a Stream-based object to identify the file. Once the object is
ready, you can use the following version of the Load() method to open it:
public virtual void Load(Stream inStream);

This method expects a Stream type of object, such as a FileStream


variable. Here is an example of calling it:
using System;
using System.IO;
using System.Xml;

namespace VideoCollection1

C# 3.0 Practical Learning II 59


{
class Program
{
static int Main(string[] args)
{
string strFilename = "Videos.xml";
XmlDocument xmlDoc = new XmlDocument();
FileStream fsVideos = null;

if (File.Exists(strFilename))
{
fsVideos = new FileStream(strFilename,
FileMode.Open,

FileAccess.Read);

xmlDoc.Load(fsVideos);
}
else
Console.WriteLine("The file {0} could not be
located",
strFilename);

return 0;
}
}
}

Programmatically Reading an XML File

Many of the XML files you encounter will have been created by someone else.
Still, because it is primarily a text document, you are expected to be able to
read any XML file and figure out its content, or at least most of it. As
mentioned already, you can open an XML file using a text editor such as
Notepad. After opening the file, you can start by checking the document
declaration, then move to other items.

Another way you can explore an XML file consists of programmatically reading
it. This is also referred to as parsing (the parser parses the document). To
support reading an XML file, the .NET Framework provides the abstract
XmlReader class as the ancestor of classes that can read an XML file. One of
the classes derived from XmlReader is called XmlTextReader. The
XmlTextReader class provides the ability to read the file from the left to the
right sides and from the top to the bottom sections. This class has very
important characteristics you must remember:

 This class proceeds with a forward only approach: it reads a character or


a word, moves to the next, and cannot refer back. This means that, after
it has visited an item and has moved ahead, you cannot use it to refer to
an item back

C# 3.0 Practical Learning II 60


 This class is read-only: you cannot use it to edit or modify an item (but,
when you get to an item, you can use another object to modify the item)

To programmatically read an XML file, you can start by declaring a variable of


type XmlTextReader using one of its constructors, including the default. To
specify the file you want to open and read, you can use the constructor
whose syntax is the following :
public XmlTextReader(string url);

When using this method, pass the name of the file or its path as argument.
Here is an example:
using System;
using System.IO;
using System.Xml;

namespace VideoCollection1
{
class Program
{
static int Main(string[] args)
{
string strFilename = "Videos.xml";

if (File.Exists(strFilename))
XmlTextReader rdrXml = new
XmlTextReader(strFilename);
else
Console.WriteLine("The file {0} could not be
located",
strFilename);

Console.WriteLine();
return 0;
}
}
}

You can also identify a file using a Stream-based object. Once the object is
ready, you can pass it to the following constructor of the class:
public XmlTextReader(Stream input);

Here is an example:
using System;
using System.IO;
using System.Xml;

namespace VideoCollection1
{
class Program
{
static int Main(string[] args)

C# 3.0 Practical Learning II 61


{
string strFilename = "Videos.xml";
FileStream fsVideos = new FileStream(strFilename,
FileMode.Open,

FileAccess.Read);

if (File.Exists(strFilename))
XmlTextReader rdrXml = new
XmlTextReader(fsVideos );
else
Console.WriteLine("The file {0} could not be
located",
strFilename);

fsVideos.Close();
Console.WriteLine();
return 0;
}
}
}

To actually read the file, the XmlTextReader is equipped with the Read()
method whose syntax is:
public override bool Read();

As you may suspect, this method only tells you that it successfully read an
item. It doesn't tell you what it read. As stated already, the XmlTextReader
scans a file in a left-right-top-down approach. When it has read something, it
returns true. If it didn't or couldn't read something, it returns false. Therefore,
you can call it to read an item. If it succeeds, it returns true. After reading
that item, you can call it again to move to the next item. If there is a next
item, it reads it and returns true. But, if there is no next item, the Read()
method would not be able to read it and it would return false. In other words,
you can ask the Read() method to continuously read the items as long as it
returns true. Once it cannot read an item, you can ask it to stop. To perform
this exercise, you can use either a while or a do...while loop. This would
be done as follows:
using System;
using System.IO;
using System.Xml;

namespace VideoCollection1
{
class Program
{
static int Main(string[] args)
{
string strFilename = "Videos.xml";
FileStream fsVideos = new FileStream(strFilename,
FileMode.Open,

C# 3.0 Practical Learning II 62


FileAccess.Read);

XmlTextReader rdrXml = new XmlTextReader(fsVideos );

do {
// Read an item and return true
// Continue reading as long as ...
} while (rdrXml.Read() == true); // ... as long as
Read() returns true
// Once Read() returns false, STOP!!!

fsVideos.Close();
Console.WriteLine();
return 0;
}
}
}

To identify what was read, the XmlTextReader provides methods appropriate


for the different types of item that an XML file can contain. Starting in the
next lesson, we will review the types of items of a file.

XML Wellformedness
 

Tag Creation

Earlier, we mentioned that XML worked through markups. A simple markup is


made of a tag created between the left angle bracket "<" and the right angle
bracket ">". Just creating a markup is not particularly significant. You must
give it meaning. To do this, you can type a number, a date, or a string on the
right side of the right angle bracket ">" symbol. The text on the right side of
">" is referred to as the item's text. It is also called a value.

After specifying the value of the markup, you must close it: this is a rule not
enforced in HTML but must be respected in XML to make it "well-formed". To
close a tag, use the same formula of creating a tag with the left angle bracket
"<", the tag, and the right angle bracket ">" except that, between < and the
tag, you must type a forward slash. The formula to use is:
<tag>some value</tag>

The item on the left side of the "some value" string, in this case <tag>, is
called the opening or start-tag. The item on the right side of the "some value"
string, in this case </tag>, is called the closing or end-tag. Like<tag> is a
markup, </tag> also is called a markup.

C# 3.0 Practical Learning II 63


With XML, you create your own tags with custom names. This means that a
typical XML file is made of various items. Here is an example:

<title>The Distinguished Gentleman</title><director>Jonathan


Lynn</director><length>112 Minutes</length>
 

Practical Learning: Creating XML

1. Since we learned about the encoding declaration already, change the


XmlDocument.Load() call as follows:
 
using System;
using System.Xml;

namespace CollegeParkAutoParts1
{
class Program
{
static int Main(string[] args)
{
XmlDocument docXML = new XmlDocument();

docXML.LoadXml("<?xml version=\"1.0\"
encoding=\"utf-8\"?>");
return 0;
}
}
}

2. Save the file

Tag Names

When creating your tags, there are various rules you must observe with
regards to their names. Unlike HTML, XML is very restrictive with its rules. For
example, unlike HTML but like C/C++/C#, XML is case-sensitive. This means
that CASE, Case, and case are three different words. Therefore, from now on,
you must pay close attention to what you write inside of the < and the >
delimiters.

Besides case sensitivity, there are some rules you must observe when naming
the tags of your markups:

 The name of a tag must be in one word, no space in the name

 The name must start with an alphabetic letter or an underscore -


Examples are <Country> or <_salary>

C# 3.0 Practical Learning II 64


 The first letter or underscore that starts a name can be followed by:

o Letters - Example: <OperatingSystem>

o Digits - Example: <L153>

o Hyphens - Example: <TV-Rating>

o Underscores - Example: <Chief_Accountant>

 The name of a tag cannot start with xml, XML or any combination of X
(uppercase or lowercase), followed by M (uppercase or lowercase), and
followed by L (uppercase or lowercase)

In our lessons, here are the rules we will apply:

 A name will start in uppercase (most of the time) or lowercase

 When a name is a combination of words, such as [hourly salary], we will


start each part in uppercase. Examples will be HourlySalary or
DateOfBirth

In future sections, we will learn that, with some markups, you can include
non-readable characters between the angle brackets. In fact, you will need to
pay close attention to the symbols you type in a markup. We will also see
how some characters have special meaning.

The Root

Every XML document must have one particular tag that, either is the only tag
in the file, or acts as the parent of all the other tags of the same document.
This tag is called the root. Here is an example of a file that has only one tag:
<rectangle>A rectangle is a shape with 4 sides and 4 straight
angles</rectangle>

This would produce:

C# 3.0 Practical Learning II 65


If there are more than one tag in the XML file, one of them must serve as the
parent or root. Otherwise, you would receive an error. Based on this rule, the
following XML code is not valid:
<rectangle>A rectangle is a shape with 4 sides and 4 straight
angles</rectangle>
<square>A square is a rectangle whose 4 sides are equal</square>

This would produce:

 To correct this type of error, you can change one of the existing tags to act
as the root. Here is an example:

C# 3.0 Practical Learning II 66


<rectangle>A rectangle is a shape with 4 sides and 4 straight
angles
<square>A square is a rectangle whose 4 sides are
equal</square></rectangle>

This would produce:

Alternatively, you can create a tag that acts as the parent for the other tags.
Here is an example:
<geometry><rectangle>A rectangle is a shape with 4 sides and 4
straight angles
</rectangle><square>A square is a rectangle whose 4 sides are
equal</square></geometry>

This would produce:

As mentioned already, a good XML file should have a Document Type


Declaration:

C# 3.0 Practical Learning II 67


<?xml version="1.0" encoding="utf-8"?><geometry><rectangle>A
rectangle
is a shape with 4 sides and 4 straight
angles</rectangle><square>A
square is a rectangle whose 4 sides are
equal</square></geometry>

To provide access to the root of an XML file, the XmlDocument class is


equipped with the DocumentElement property.

The Structure of an XML Tag


 

Empty Tags

We mentioned that, unlike HTML, every XML tag must be closed. We also saw
that the value of a tag was specified on the right side of the right angle
bracket of the start tag. In some cases, you will create a tag that doesn't
have a value or, may be for some reason, you don't provide a value to it.
Here is an example:
<dinner></dinner>

This type of tag is called an empty tag. Since there is no value in it, you may
not need to provide an end tag but it still must be closed. Although this
writing is allowed, an alternative is to close the start tag itself. To do this,
between the tag name and the right angle bracket, type an empty space
followed by a forward slash. Based on this, the above line can be written as
follows:
<dinner />

Both produce the same result or accomplish the same role.

White Spaces

In the above example, we typed various items on the same line. If you are
creating a long XML document, although creating various items on the same
line is acceptable, this technique can make it (very) difficult to read. One way
you can solve this problem is to separate tags with empty spaces. Here is an
example:
<title>The Distinguished Gentleman</title> <director>Jonathan
Lynn</director> <length>112 Minutes</length>

Yet a better solution consists of typing each item on its own line. This would
make the document easier to read. Here is an example:
<title>The Distinguished Gentleman</title>
<director>Jonathan Lynn</director>

C# 3.0 Practical Learning II 68


<length>112 Minutes</length>

All these are possible and acceptable because the XML parser doesn't
consider the empty spaces or end of line. Therefore, to make your code
easier to read, you can use empty spaces, carriage-return-line-feed
combinations, or tabs inserted in various sections. All these are referred to as
white spaces.

Nesting Tags

Most XML files contain more than one tag. We saw that a tag must have a
starting point and a tag must be closed. One tag can be included in another
tag: this is referred to as nesting. A tag that is created inside of another tag is
said to be nested. A tag that contains another tag is said to be nesting.
Consider the following example:
<Smile>Please smile to the camera</Smile>
<English>Welcome to our XML Class</English>
<French>Bienvenue à notre Classe XML</French>

In this example, you may want the English tag to be nested in the Smile tag.
To nest one tag inside of another, you must type the nested tag before the
end-tag of the nesting tag. For example, if you want to nest the English tag in
the Smile tag, you must type the whole English tag before the </Smile> end
tag. Here is an example:
<Smile>Please smile to the camera<English>Welcome to our XML
Class</English></Smile>

To make this code easier to read, you can use white spaces as follows:
<smile>Please smile to the camera
<English>Welcome to our XML Class</English>
</smile>

When a tag is nested, it must also be closed before its nesting tag is closed.
Based on this rule, the following code is not valid:
<Smile>Please smile to the camera
<English>Welcome to our XML Class
</Smile>
</English>

The rule broken here is that the English tag that is nested in the the Smile tag
is not closed inside the Smile tag but outside.

Practical Learning: Creating XML

1. To apply the concept of nesting XML tags, change the Parts.xml file as
follows:
 

C# 3.0 Practical Learning II 69


<?xml version="1.0" encoding="utf-8" ?>
<Parts>
<Part>
<CarYear>2005</CarYear>
<Make>Acura</Make>
<Model>MDX 3.5 4WD</Model>
<PartNumber>293749</PartNumber>
<PartName>Air Filter</PartName>
<UnitPrice>16.85</UnitPrice>
</Part>
<Part>
<CarYear>2002</CarYear>
<Make>Audi</Make>
<Model>A4 Quattro</Model>
<PartNumber>283759</PartNumber>
<PartName>Clutch Release Bearing</PartName>
<UnitPrice>55.50</UnitPrice>
</Part>
</Parts>

2. Access the Program.cs file and change the call to the


XmlDocument.Load() method as follows:
 
using System;
using System.Xml;

namespace CollegeParkAutoParts1
{
class Program
{
static int Main(string[] args)
{
XmlDocument docXML = new XmlDocument();

docXML.LoadXml("<?xml version=\"1.0\"
encoding=\"utf-8\"?>" +
"<Employees><Employee>" +
"<EmplNumber>48-705</EmplNumber>" +
"<FirstName>John</FirstName>" +
"<LastName>Cranston</LastName>" +
"<HourlySalary>16.48</HourlySalary>"
+
"</Employee><Employee>" +
"<EmplNumber>22-688</EmplNumber>" +
"<FirstName>Annie</FirstName>" +
"<LastName>Loskar</LastName>" +
"<HourlySalary>12.50</HourlySalary>"
+
"</Employee><Employee>" +
"<EmplNumber>85-246</EmplNumber>" +
"<FirstName>Bernie</FirstName>" +
"<LastName>Christo</LastName>" +
"<HourlySalary>22.52</HourlySalary>"
+

C# 3.0 Practical Learning II 70


"</Employee><Employee></Employees>" );

docXML.Save("Employees.xml");
return 0;
}
}
}

3. Execute the application

4. Close the DOS window

5. Open Windows Explorer and display the contents of the folder of the
current project.
Notice the presence of the parts.xml and the Employees.xml files

6. Double-click each file to preview it in the browser

C# 3.0 Practical Learning II 71


The Nodes of an XML
Element
 

An XML Node
 

Introduction to XML Nodes

Consider the following example of an XML file named Videos.xml:


<?xml version="1.0" encoding="utf-8" ?>
<Videos>
<Video>
<Title>The Distinguished Gentleman</Title>
<Director>Jonathan Lynn</Director>
<Length>112 Minutes</Length>

<Format>DVD</Format>

<Rating>R</Rating>
</Video>
<Video>
<Title>Her Alibi</Title>
<Director>Bruce Beresford</Director>
<Length>94 Mins</Length>
<Format>DVD</Format>
<Rating>PG-13</Rating>
</Video>
<Video>
<Title>Chalte Chalte</Title>
<Director>Aziz Mirza</Director>
<Length>145 Mins</Length>
<Format>DVD</Format>
<Rating>N/R</Rating>
</Video>
</Videos>

An XML file appears as an upside-down tree: it has a root (in this case
<Videos>), it can have branches (in this case <Video>), and it can have
leaves (an example in this case is <Title>). As we have seen so far, all of
these objects are created using the same technique: a tag with a name (such
as <Title>) and an optional value. Based on their similarities, each of these

C# 3.0 Practical Learning II 72


objects is called a node. To support nodes of an XML file, the .NET
Framework provides the XmlNode class, which is the ancestor to all types of
nodes. XmlNode is an abstract class without a constructor. Based on this, to
get a node, you must have an object that would produce one and you can
only retrieve a node from an (existing) object.

Introduction to Node Types

To make XML as complete and as efficient as possible, it can contain various


types of nodes. The categories or possible types of nodes are identified by an
enumeration named XmlNodeType. If you use an XmlTextReader object to
scan a file, when calling Read(), the class has a property named NodeType
that allows you to identify the node that was read. NodeType is a read-only
property of type XmlNodeType and it is declared as follows:
public override XmlNodeType NodeType { get; }

Therefore, when calling the XmlTextReader.Read() method, you can


continuously check the value of the XmlTextReader.NodeType property to
find out what type of node was just read, and then you can take an
appropriate action.

Elements Fundamentals
 

Introduction

An element in an XML document is an object that begins with a start-tag,


may contain a value, and may terminate with an end-tag. Based on this, the
combination of a start-tag, the value, and the end-tag is called an element.
An element can be more than that but for now, we will consider that an
element is primarily characterized by a name and possibly a value.

To support XML elements, the System.Xml namespace provides the


XmlElement class. XmlElement is based on a class named XmlLinkedNode
that itself is based on XmlNode. To access an XML element, you can declare a
variable of type XmlElement but the main purpose of this class is to get an
element from a DOM object. For this reason, the XmlElement class doesn't
have a constructor you can use. Instead, and as we will learn, the other
classes have methods that produce an XmlElement element you can
manipulate as necessary.

In the previous lesson, we saw that every XML file must have a root and we
mentioned that you could call the XmlDocument.DocumentElement
property to access it. This property is of type XmlElement and, to access it,

C# 3.0 Practical Learning II 73


you can declare an XmlElement variable and assign it this property. Here is
an example:
using System;
using System.IO;
using System.Xml;

namespace VideoCollection1
{
class Program
{
static int Main(string[] args)
{
string strFilename = "Videos.xml";
XmlDocument xmlDoc = new XmlDocument();

if (File.Exists(strFilename))
{
xmlDoc.Load(strFilename);
XmlElement elm = xmlDoc.DocumentElement;
Console.WriteLine("{0}", elm);
}
else
Console.WriteLine("The file {0} could not be
located",
strFilename);

Console.WriteLine();
return 0;
}
}
}

This would produce:


System.Xml.XmlElement

Press any key to continue . . .

An XML element is represented in the XmlNodeType enumeration as the


Element member. When using the Read() method of an XmlTextReader
object, to find out if the item being read is an element, you can check
whether the member of the current XmlNodeType is Element. Here is an
example:
using System;
using System.IO;
using System.Xml;

namespace VideoCollection1
{
class Program
{
static int Main(string[] args)
{

C# 3.0 Practical Learning II 74


string strFilename = "Videos.xml";
XmlDocument xmlDoc = new XmlDocument();

if (File.Exists(strFilename))
{
XmlTextReader rdrXml = new
XmlTextReader(strFilename);

do {
switch (rdrXml.NodeType)
{
case XmlNodeType.Element:
break;
}
}while (rdrXml.Read());
}
else
Console.WriteLine("The file {0} could not be
located",
strFilename);

Console.WriteLine();
return 0;
}
}
}

Practical Learning: Introducing XML Elements

1. Start Microsoft Visual C# and create a Console Application named


CollegeParkAutoParts2

2. On the main menu, click Project -> Add New Item...

3. In the Templates list, click XML File

4. Set the Name to makes and click Add

5. Change the file as follows:


 
<?xml version="1.0" encoding="utf-8"?>
<Makes>
<Make>Acura</Make>
<Make>Audi</Make>
<Make>BMW</Make>
<Make>Chevrolet</Make>
</Makes>

6. On the main menu, click File -> Save makes.xml As...

7. Access the main folder of the current project and, inside of it, open a
sub-folder of the same name (it should be opened already). In the sub-
folder of the same name, open the bin sub-folder followed by the

C# 3.0 Practical Learning II 75


Release sub-folder
 

8. Click Save

The Name of an Element

The name of an element is the string that represents the tag. For example, in
<Director>, the word Director is the name of the element. An element must
have at least a start-tag. All of the tags we have seen so far were created as
elements. When creating your elements, remember to follow the rules we
defined for names.

The XmlElement class is equipped with the Name property that can be used
to identify an existing element. Here is an example of accessing it:
using System;
using System.IO;
using System.Xml;

namespace VideoCollection1
{
class Program
{
static int Main(string[] args)
{
string strFilename = "Videos.xml";
XmlDocument xmlDoc = new XmlDocument();

if (File.Exists(strFilename))

C# 3.0 Practical Learning II 76


{
xmlDoc.Load(strFilename);
XmlElement elm = xmlDoc.DocumentElement;
Console.WriteLine("{0}", elm.Name);
}
else
Console.WriteLine("The file {0} could not be
located",
strFilename);

Console.WriteLine();
return 0;
}
}
}

This would produce:


Videos

Press any key to continue . . .

Notice that Videos is returned as the name of the root element of the file. If
calling the Read() method of an XmlTextReader object to scan a file, when
you get to an element, you can find out its Name identity by accessing it.
Here is an example:
using System;
using System.IO;
using System.Xml;

namespace VideoCollection1
{
class Program
{
static int Main(string[] args)
{
string strFilename = "Videos.xml";
XmlDocument xmlDoc = new XmlDocument();

if (File.Exists(strFilename))
{
XmlTextReader rdrXml = new
XmlTextReader(strFilename);

do {
switch (rdrXml.NodeType)
{
case XmlNodeType.Element:
Console.WriteLine("{0}",
rdrXml.Name);
break;
}
}while (rdrXml.Read());
}
else

C# 3.0 Practical Learning II 77


Console.WriteLine("The file {0} could not be
located",
strFilename);

Console.WriteLine();
return 0;
}
}
}

This would produce:


Videos
Video
Title
Director
Length
Format
Rating
Video
Title
Director
Length
Format
Rating
Video
Title
Director
Length
Format
Rating

Press any key to continue . . .

The Text or Value of an Element

The value of an element is the item displayed on the right side of the start-
tag. It is also called the text of the element. In the case of
<Director>Jonathan Lynn</Director>, the "Jonathan Lynn" string is the
value of the Director element. To support the text or value of an element, the
XmlElement class is equipped with the Value property.

While the value of one element can be a number, the value of another
element can be a date. Yet another element can use a regular string as its
value. Consider the following example:
<?xml version="1.0" encoding="utf-8" ?>
<Employees>
<Employee>
<FullName>Lydia Thomason</FullName>
<Salary>25.64</Salary>
<DepartmentID>1</DepartmentID>
</Employee>
<Employee>

C# 3.0 Practical Learning II 78


<FullName>June Grath</FullName>
<Salary>16.38</Salary>
<DepartmentID>4</DepartmentID>
</Employee>
</Employees>

Notice that the Salary elements contain numbers that look like currency
values and the DepartmentID elements use an integer as value.

If you are using an XmlTextReader object to scan a file, when the Read()
method gets to an element, you can find out what its value is by accessing
this property. Here is an example:
using System;
using System.IO;
using System.Xml;

namespace VideoCollection1
{
class Program
{
static int Main(string[] args)
{
string strFilename = "Videos.xml";
XmlDocument xmlDoc = new XmlDocument();

if (File.Exists(strFilename))
{
XmlTextReader rdrXml = new
XmlTextReader(strFilename);

do {
switch (rdrXml.NodeType)
{
case XmlNodeType.Text:
Console.WriteLine("{0}",
rdrXml.Value);
break;
}
}while (rdrXml.Read());
}
else
Console.WriteLine("The file {0} could not be
located",
strFilename);

Console.WriteLine();
return 0;
}
}
}

This would produce:


The Distinguished Gentleman
Jonathan Lynn

C# 3.0 Practical Learning II 79


112 Minutes
DVD
R
Her Alibi
Bruce Beresford
94 Mins
DVD
PG-13
Chalte Chalte
Aziz Mirza
145 Mins
DVD
N/R

Press any key to continue . . .

The value or text of an element is an object of type XmlText.

Practical Learning: Getting the Text of an Element

1. Access the Program.cs file and change it as follows::


 
using System;
using System.IO;
using System.Xml;

namespace CollegeParkAutoParts2
{
class Program
{
static int Main(string[] args)
{
FileStream fsCPAP = null;
string strFilename = "makes.xml";
XmlDocument xmlDoc = new XmlDocument();

if (File.Exists(strFilename))
{
fsCPAP = new FileStream(strFilename,
FileMode.Open,
FileAccess.Read);
XmlTextReader rdrXml = new
XmlTextReader(fsCPAP);

do
{
switch (rdrXml.NodeType)
{
case XmlNodeType.Text:
Console.WriteLine("Make: {0}",
rdrXml.Value);
break;

C# 3.0 Practical Learning II 80


}
} while (rdrXml.Read());
}
else
Console.WriteLine("The {0} file was not found",
strFilename);

Console.WriteLine();
return 0;
}
}
}

2. Execute the application to see the result. This would produce:


 
Make: Acura
Make: Audi
Make: BMW
Make: Chevrolet

Press any key to continue . . .

3. Close the DOS window

Empty Elements

An element may not have a value but only a name. Consider the following
example:
<?xml version="1.0" encoding="utf-8"?>
<Videos>
<Video>
<Title>The Distinguished Gentleman</Title>
<Director>Jonathan Lynn</Director>
</Video>
</Videos>

In this case, the Video element doesn't have a value. It is called an empty
element. When a tag is empty, the Value property of its XmlElement object
would return an empty value. Consider the following code:
using System;
using System.IO;
using System.Xml;

namespace VideoCollection1
{
class Program
{
static int Main(string[] args)
{
string strFilename = "Videos.xml";
XmlDocument xmlDoc = new XmlDocument();

C# 3.0 Practical Learning II 81


if (File.Exists(strFilename))
{
xmlDoc.Load(strFilename);
XmlElement elm = xmlDoc.DocumentElement;
Console.WriteLine("{0}", elm.Value);
}
else
Console.WriteLine("The file {0} could not be
located",
strFilename);

Console.WriteLine();
return 0;
}
}
}

This would produce:


Press any key to continue . . .

Because the Videos node doesn't have its own value, its Value property
returns an empty string.

Character Entities in an Element Value

Besides these obvious types of values, you may want to display special
characters as values of elements. Consider the following example:
<?xml version="1.0" encoding="utf-8" ?>
<Employees>
<Employee>
<FullName>Sylvie <Bellie> Aronson</FullName>
<Salary>25.64</Salary>
<DepartmentID>1</DepartmentID>
</Employee>
<Employee>
<FullName>Bertrand Yamaguchi</FullName>
<Salary>16.38</Salary>
<DepartmentID>4</DepartmentID>
</Employee>
</Employees>

If you try using this XML document, for example, if you try displaying it in a
browser, you would, receive an error:

C# 3.0 Practical Learning II 82


The reason is that when the parser reaches the <FullName>Sylvie <Bellie>
Aronson</FullName> line, it thinks that <Bellie> is a tag but then <Bellie> is
not closed. The parser concludes that the document is not well-formed, that
there is an error. For this reason, to display a special symbol as part of a
value, you can use its character code. For example, the < (less than)
character is represented with &lt and the > (greater than) symbol can be
used with &gt;. Therefore, the above code can be corrected as follows:
<?xml version="1.0" encoding="utf-8" ?>
<Employees>
<Employee>
<FullName>Sylvie &lt;Bellie&gt; Aronson</FullName>
<Salary>25.64</Salary>
<DepartmentID>1</DepartmentID>
</Employee>
<Employee>
<FullName>Bertrand Yamaguchi</FullName>
<Salary>16.38</Salary>
<DepartmentID>4</DepartmentID>
</Employee>
</Employees>

This would produce:

C# 3.0 Practical Learning II 83


Here is a list of other codes you can use for special characters:

Code Symbol Code Symbol Code Symbol Code Symbol Code Symbol

&apos; ' &#067; C &#106; j &#179; ³ &#218; Ú

&lt; < &#068; D &#107; k &#180; ´ &#219; Û

&gt; > &#069; E &#108; l &#181; ´ &#220; Ü

&amp; & &#070; F &#109; m &#182; ¶ &#221; Ý

&quot; " &#071; G &#110; n &#183; · &#222; Þ

&#033; ! &#072; H &#111; o &#184; ¸ &#223; ß

&#034; " &#073; I &#112; p &#185; ¹ &#224; á

&#035; # &#074; J &#113; q &#186; º &#225; à

C# 3.0 Practical Learning II 84


&#036; $ &#075; K &#114; r &#187; » &#226; â

&#037; % &#076; L &#115; s &#188; ¼ &#227; ã

&#038; & &#077; M &#116; t &#189; ½ &#228; ä

&#039; ' &#078; N &#117; u &#190; ¾ &#229; å

&#040; ( &#079; O &#118; v &#191; ¿ &#230; æ

&#041; ) &#080; P &#119; w &#192; À &#231; ç

&#042; * &#081; Q &#120; x &#193; Á &#232; è

&#043; + &#082; R &#121; y &#194; Â &#233; é

&#044; , &#083; S &#122; z &#195; Ã &#234; ê

&#045; - &#084; T &#123; { &#196; Ä &#235; ë

&#046; . &#085; U &#125; } &#197; Å &#236; ì

&#047; / &#086; V &#126; ~ &#198; Æ &#237; í

&#048; 0 &#087; W &#160; empty &#199; Ç &#238; î

&#049; 1 &#088; X &#161; ¡ &#200; È &#239; ï

&#050; 2 &#089; Y &#162; ¢ &#201; É &#240; ð

&#051; 3 &#090; Z &#163; £ &#202; Ê &#241; ñ

&#052; 4 &#091; [ &#164; ¤ &#203; Ë &#242; ò

C# 3.0 Practical Learning II 85


&#053; 5 &#092; \ &#165; ¥ &#204; Ì &#243; ó

&#054; 6 &#093; ] &#166; ¦ &#205; Í &#244; ô

&#055; 7 &#094; ^ &#167; § &#206; Î &#245; õ

&#056; 8 &#095; _ &#168; ¨ &#207; Ï &#246; ö

&#057; 9 &#096; ` &#169; © &#208; Ð &#247; ÷

&#058; : &#097; a &#170; ª &#209; Ñ &#248; ø

&#059; ; &#098; b &#171; « &#210; Ò &#249; ù

&#060; < &#099; c &#172; ¬ &#211; Ó &#250; ú

&#061; = &#100; d &#173; &#212; Ô &#251; û

&#062; > &#101; e &#174; ® &#213; Õ &#252; ü

&#063; ? &#102; f &#175; ¯ &#214; Ö &#253; ý

&#064; @ &#103; g &#176; ° &#215; × &#254; þ

&#065; A &#104; h &#177; ± &#216; Ø &#255; ÿ

&#066; B &#105; i &#178; ² &#217; Ù &#256; A

There are still other codes to include special characters in an XML file.

Practical Learning: Introducing XML Elements

C# 3.0 Practical Learning II 86


1. In the Solution Explorer, right-click CollegeParkAutoParts2 -> Add ->
New Item...

2. In the Templates list, make sure XML File is selected.


Set the Name to models and click Add

3. To save the file, on the main menu, click File -> Save models.xml As...

4. Access the main folder of the current project and, inside of it, open a
sub-folder of the same name (it should be selected already). In the sub-
folder of the same name, open the bin sub-folder followed by the
Release sub-folder. Click Save

5. Change the file as follows:


 
<?xml version="1.0" encoding="utf-8" ?>
<Models>
<Model>NSX</Model>
<Model>TL</Model>
<Model>Spider</Model>
<Model>A4</Model>
<Model>RS6</Model>
<Model>323I</Model>
<Model>M5</Model>
<Model>Astro</Model>
<Model>Cavalier</Model>
<Model>Prot&#233;g&#233;</Model>
</Models>

6. Access the Program.cs file and modify it as follows:


 
using System;
using System.IO;
using System.Xml;

namespace CollegeParkAutoParts2
{
class Program
{
static int Main(string[] args)
{
FileStream fsCPAP = null;
string strFilename = "models.xml";
XmlDocument xmlDoc = new XmlDocument();

if (File.Exists(strFilename))
{
fsCPAP = new FileStream(strFilename,
FileMode.Open,
FileAccess.Read);
XmlTextReader rdrXml = new
XmlTextReader(fsCPAP);

C# 3.0 Practical Learning II 87


do
{
switch (rdrXml.NodeType)
{
case XmlNodeType.Text:
Console.WriteLine("Model: {0}",
rdrXml.Value);
break;
}
} while (rdrXml.Read());
}
else
Console.WriteLine("The {0} file was not found",
strFilename);

Console.WriteLine();
return 0;
}
}
}

7. Execute the application to see the result:


 
Model: NSX
Model: TL
Model: Spider
Model: A4
Model: RS6
Model: 323I
Model: M5
Model: Astro
Model: Cavalier
Model: Protégé

Press any key to continue . . .

8. Close the DOS window

Identifying the Markup of a Node


 

The Inner Text of a node

In the previous sections, we have seen how to create a tag to produce a


node. We also saw that a node could be placed inside of another node. The
combined text of the values of the children of a node is available through its
XmlNode.InnerText property which is declared as follows:

public virtual string InnerText{get; set};

C# 3.0 Practical Learning II 88


This property concatenates the values of the children of the node that called
them and doesn't include their markups. Here is an example:
using System;
using System.IO;
using System.Xml;

namespace VideoCollection1
{
class Program
{
static int Main(string[] args)
{
string strFilename = "Videos.xml";
XmlDocument xmlDoc = new XmlDocument();

if (File.Exists(strFilename))
{
xmlDoc.Load(strFilename);
XmlElement elm = xmlDoc.DocumentElement;
Console.WriteLine("{0}", elm.InnerText);
}
else
Console.WriteLine("The file {0} could not be
located",
strFilename);

Console.WriteLine();
return 0;
}
}
}

This would produce:


The Distinguished GentlemanJonathan Lynn112 MinutesDVDRHer
AlibiBruce Beresford9
4 MinsDVDPG-13Chalte ChalteAziz Mirza145 MinsDVDN/R

Press any key to continue . . .

Notice that this property produces all values of the children of a node in one
block. We already saw how to access each value of the children of a node by
calling the XmlTextReader.Read() method and get its Text.

The Outer XML Code of a node

If you want to get a node, its markup, its child(ren) and its(their) markup(s),
you can access its XmlNode.OuterXml property which is declared as follows:
public virtual string OuterXml{get};

Here is an example:

C# 3.0 Practical Learning II 89


using System;
using System.IO;
using System.Xml;

namespace VideoCollection1
{
class Program
{
static int Main(string[] args)
{
string strFilename = "Videos.xml";
XmlDocument xmlDoc = new XmlDocument();

if (File.Exists(strFilename))
{
xmlDoc.Load(strFilename);
XmlElement elm = xmlDoc.DocumentElement;
Console.WriteLine("{0}", elm.OuterXml);
}
else
Console.WriteLine("The file {0} could not be
located",
strFilename);

Console.WriteLine();
return 0;
}
}
}

This would produce:


<Videos><Video><Title>The Distinguished
Gentleman</Title><Director>Jonathan Lynn
</Director><Length>112
Minutes</Length><Format>DVD</Format><Rating>R</Rating></V
ideo><Video><Title>Her Alibi</Title><Director>Bruce
Beresford</Director><Length>
94 Mins</Length><Format>DVD</Format><Rating>PG-
13</Rating></Video><Video><Title>
Chalte Chalte</Title><Director>Aziz Mirza</Director><Length>145
Mins</Length><Fo
rmat>DVD</Format><Rating>N/R</Rating></Video></Videos>

Press any key to continue . . .

The Inner XML Code of a node

If you want only the markup(s) of the child(ren) excluding the parent, access
its XmlNode.InnerXml property which is declared as follows:
public virtual string InnerXml{get};

Here is an example:

C# 3.0 Practical Learning II 90


Console.WriteLine("{0}", elm.InnerXml);

This would produce:


<Video><Title>The Distinguished
Gentleman</Title><Director>Jonathan Lynn</Direct
or><Length>112
Minutes</Length><Format>DVD</Format><Rating>R</Rating></Video><V
i
deo><Title>Her Alibi</Title><Director>Bruce
Beresford</Director><Length>94 Mins<
/Length><Format>DVD</Format><Rating>PG-
13</Rating></Video><Video><Title>Chalte C
halte</Title><Director>Aziz Mirza</Director><Length>145
Mins</Length><Format>DVD
</Format><Rating>N/R</Rating></Video>

Press any key to continue . . .

The  Child Nodes of  a Node


 

Introduction

As mentioned already, one node can be nested inside of another. A nested


node is called a child of the nesting node. This also implies that a node can
have as many children as necessary, making them child nodes of the parent
node. In our Videos.xml example, the Title and the Director nodes are
children of the Video node. The Video node is the parent of both the Title and
the Director nodes.

A Collection of Child Nodes

To support the child nodes of a particular node, the XmlNode class is


equipped with the ChildNodes property. To identify the collection of child
nodes of a node, the .NET Framework provides the XmlNodeList class.
Therefore, the ChildNodes property of an XmlNode object is of type
XmlNodeList. This property is declared as follows:

public virtual XmlNodeList ChildNodes{get};

When this property is used, it produces an XmlNodeList list, which is a


collection of all nodes that share the same parent. Each item in the collection
is of type XmlNode. To give you the number of nodes on an XmlNodeList
collection, the class is equipped with a property named Count. Here is an
example of using it:

using System;
using System.IO;

C# 3.0 Practical Learning II 91


using System.Xml;

namespace VideoCollection
{
class Program
{
static int Main(string[] args)
{
string strFilename = "Videos.xml";
XmlDocument xmlDoc = new XmlDocument();

if (File.Exists(strFilename))
{
xmlDoc.Load(strFilename);
XmlElement elm = xmlDoc.DocumentElement;
XmlNodeList lstVideos = elm.ChildNodes;

Console.WriteLine("The root element contains {0}


nodes",
lstVideos.Count);
}
else
Console.WriteLine("The file {0} could not be
located",
strFilename);

Console.WriteLine();
return 0;
}
}
}

This would produce:


The root element contains 3 nodes

Press any key to continue . . .

You can also use the Count property in a for loop to visit the members of
the collection.

Accessing a Node in a Collection

The children of a node, that is, the members of a ChildNodes property, or


the members of an XmlNodeList collection, can be located each by an index.
The first node has an index of 0, the second has an index of 1, an so on. To
give you access to a node of the collection, the XmlNodeList class is
equipped with an indexed property and a method named Item. Both produce
the same result. For example, if a node has three children, to access the
third, you can apply an index of 2 to its indexed property. Here is an
example:
using System;

C# 3.0 Practical Learning II 92


using System.IO;
using System.Xml;

namespace VideoCollection
{
class Program
{
static int Main(string[] args)
{
string strFilename = "Videos.xml";
XmlDocument xmlDoc = new XmlDocument();

if (File.Exists(strFilename))
{
xmlDoc.Load(strFilename);
XmlElement elm = xmlDoc.DocumentElement;
XmlNodeList lstVideos = elm.ChildNodes;

Console.WriteLine(lstVideos[2]);;

}
else
Console.WriteLine("The file {0} could not be
located",
strFilename);

Console.WriteLine();
return 0;
}
}
}

You can also use the Item() method to get the same result. Using a for
loop, you can access each node and display the values of its children as
follows:
using System;
using System.IO;
using System.Xml;

namespace VideoCollection
{
class Program
{
static int Main(string[] args)
{
string strFilename = "Videos.xml";
XmlDocument xmlDoc = new XmlDocument();

if (File.Exists(strFilename))
{
xmlDoc.Load(strFilename);
XmlElement elm = xmlDoc.DocumentElement;
XmlNodeList lstVideos = elm.ChildNodes;

for (int i = 0; i < lstVideos.Count; i++)

C# 3.0 Practical Learning II 93


Console.WriteLine("{0}",lstVideos[i].InnerText );
}
else
Console.WriteLine("The file {0} could not be
located",
strFilename);

Console.WriteLine();
return 0;
}
}
}

This would produce:


The Distinguished GentlemanJonathan Lynn112 MinutesDVDR
Her AlibiBruce Beresford94 MinsDVDPG-13
Chalte ChalteAziz Mirza145 MinsDVDN/R

Press any key to continue . . .

Instead of using the indexed property, the XmlNodeList class implements


the IEnumerable interface. This allows you to use a foreach loop to visit
each node of the collection. Here is an example:
using System;
using System.IO;
using System.Xml;

namespace VideoCollection
{
class Program
{
static int Main(string[] args)
{
string strFilename = "Videos.xml";
XmlDocument xmlDoc = new XmlDocument();

if (File.Exists(strFilename))
{
xmlDoc.Load(strFilename);
XmlElement elm = xmlDoc.DocumentElement;
XmlNodeList lstVideos = elm.ChildNodes;

foreach(XmlNode node in lstVideos)


Console.WriteLine("{0}", node);
}
else
Console.WriteLine("The file {0} could not be
located",
strFilename);

Console.WriteLine();
return 0;
}

C# 3.0 Practical Learning II 94


}
}

This would produce:


System.Xml.XmlElement
System.Xml.XmlElement
System.Xml.XmlElement

Press any key to continue . . .

To better manage and manipulate the nodes of a collection of nodes, you


must be able to access the desired node. The XmlNode combined with the
XmlNodeList classes provide various means of getting to a node and taking
the appropriate actions.

The Parent of a Node

Not all nodes have children, obviously. For example, the Title node of our
Videos.xml file doesn't have children. To find out whether a node has
children, check its HasChildNodes Boolean property that is declared as
follows:
public virtual bool HasChildNodes{get};

If a node is a child, to get its parent, you can access its ParentNode
property.

The First Child Node

The children of a nesting node are also recognized by their sequence. For our
Videos.xml file, the first line is called the first child of the DOM. This would
be:
<?xml version="1.0" encoding="utf-8"?>

After identifying or locating a node, the first node that immediately follows it
is referred to as its first child. In our Videos.xml file, the first child of the first
Video node is the <Title>The Distinguished Gentleman</Title> element. The
first child of the second Video> node is <Title>Her Alibi</Title>.

In the .NET Framework, the first child of a node can be retrieved by accessing
the XmlNode.FirstChild property declared as follows:
public virtual XmlNode FirstChild{get};

In the following example, every time the parser gets to a Video node, it
displays the value of it first child:
using System;
using System.IO;
using System.Xml;

C# 3.0 Practical Learning II 95


namespace VideoCollection
{
class Program
{
static int Main(string[] args)
{
string strFilename = "Videos.xml";
XmlDocument xmlDoc = new XmlDocument();

if (File.Exists(strFilename))
{
xmlDoc.Load(strFilename);
XmlElement elm = xmlDoc.DocumentElement;
XmlNodeList lstVideos = elm.ChildNodes;

for (int i = 0; i < lstVideos.Count; i++)


Console.WriteLine("{0}",
lstVideos[i].FirstChild.InnerText );
}
else
Console.WriteLine("The file {0} could not be
located",
strFilename);

Console.WriteLine();
return 0;
}
}
}

This would produce:


The Distinguished Gentleman
Her Alibi
Chalte Chalte

Press any key to continue . . .

In this example, we started our parsing on the root node of the document. At
times, you will need to consider only a particular node, such as the first child
of a node. For example, you may want to use only the first child of the root.
To get it, you can access the FirstChild property of the DocumentElement
object of the DOM. Once you get that node, you can then do what you judge
necessary. In the following example, only the values of the child nodes of the
first child of the root are displayed:
using System;
using System.IO;
using System.Xml;

namespace VideoCollection
{
class Program
{

C# 3.0 Practical Learning II 96


static int Main(string[] args)
{
string strFilename = "Videos.xml";
XmlDocument xmlDoc = new XmlDocument();

if (File.Exists(strFilename))
{
xmlDoc.Load(strFilename);
XmlNode node =
xmlDoc.DocumentElement.FirstChild;
XmlNodeList lstVideos = node.ChildNodes;

for (int i = 0; i < lstVideos.Count; i++)


Console.WriteLine("{0}",
lstVideos[i].InnerText );
}
else
Console.WriteLine("The file {0} could not be
located",
strFilename);

Console.WriteLine();
return 0;
}
}
}

This would produce:


The Distinguished Gentleman
Jonathan Lynn
112 Minutes
DVD
R

Press any key to continue . . .

Consider the following modification of the Videos.xml file:


<?xml version="1.0" encoding="utf-8" ?>
<Videos>
<Video>
<Title>The Distinguished Gentleman</Title>
<Director>Jonathan Lynn</Director>
<CastMembers>
<Actor>Eddie Murphy</Actor>
<Actor>Lane Smith</Actor>
<Actor>Sheryl Lee Ralph</Actor>
<Actor>Joe Don Baker</Actor>
<Actor>Victoria Rowell</Actor>
</CastMembers>
<Length>112 Minutes</Length>
<Format>DVD</Format>
<Rating>R</Rating>
</Video>
<Video>

C# 3.0 Practical Learning II 97


<Title>Her Alibi</Title>
<Director>Bruce Beresford</Director>
<Length>94 Mins</Length>
<Format>DVD</Format>
<Rating>PG-13</Rating>
</Video>
<Video>
<Title>Chalte Chalte</Title>
<Director>Aziz Mirza</Director>
<Length>145 Mins</Length>
<Format>DVD</Format>
<Rating>N/R</Rating>
</Video>
</Videos>

Remember that when using a for or a foreach loop applied to an


XmlNodeList collection, each node that you access is a complete XmlNode
object and may have children. This means that you can further get the
ChildNodes node of any node. Here is an example that primarily scans the
nodes but looks for one whose name is CastMembers:
using System;
using System.IO;
using System.Xml;

namespace VideoCollection
{
class Program
{
static int Main(string[] args)
{
string strFilename = "Videos.xml";
XmlDocument xmlDoc = new XmlDocument();

if (File.Exists(strFilename))
{
xmlDoc.Load(strFilename);
// Locate the root node and
// get a reference to its first child
XmlNode node =
xmlDoc.DocumentElement.FirstChild;
// Create a list of the child nodes of
// the first node under the root
XmlNodeList lstVideos = node.ChildNodes;

// Visit each node


for (int i = 0; i < lstVideos.Count; i++)
{
// Look for a node named CastMembers
if (lstVideos[i].Name == "CastMembers")
{
// Once/if you find it,
// 1. Access its first child
// 2. Create a list of its child nodes
XmlNodeList lstActors =

C# 3.0 Practical Learning II 98


lstVideos[i].ChildNodes;
// Display the values of the nodes
for (int j = 0; j < lstActors.Count; j+
+)
Console.WriteLine("{0}",
lstActors[j].InnerText);
}
}
}
else
Console.WriteLine("The file {0} could not be
located",
strFilename);

Console.WriteLine();
return 0;
}
}
}

This would produce:


Eddie Murphy
Lane Smith
Sheryl Lee Ralph
Joe Don Baker
Victoria Rowell

Press any key to continue . . .

As we have learned that a node or a group of nodes can be nested inside of


another node. When you get to a node, you may know or find out that it has
children. You may then want to consider only the first child. Here is an
example:
using System;
using System.IO;
using System.Xml;

namespace VideoCollection
{
class Program
{
static int Main(string[] args)
{
string strFilename = "Videos.xml";
XmlDocument xmlDoc = new XmlDocument();

if (File.Exists(strFilename))
{
xmlDoc.Load(strFilename);
// Locate the root node and
// get a reference to its first child
XmlNode node =
xmlDoc.DocumentElement.FirstChild;
// Create a list of the child nodes of

C# 3.0 Practical Learning II 99


// the first node under the root
XmlNodeList lstVideos = node.ChildNodes;

// Visit each node


for (int i = 0; i < lstVideos.Count; i++)
{
// Look for a node named CastMembers
if (lstVideos[i].Name == "CastMembers")
{
// Once/if you find it,
// 1. Access its first child
// 2. Create a list of its child nodes
XmlNodeList lstActors =
lstVideos[i].FirstChild.ChildNodes;
// Display the value of its first child
node
for (int j = 0; j < lstActors.Count; j+
+)
Console.WriteLine("{0}",
lstActors[j].InnerText);
}
}
}
else
Console.WriteLine("The file {0} could not be
located",
strFilename);

Console.WriteLine();
return 0;
}
}
}

This would produce:


Eddie Murphy

Press any key to continue . . .

The Last Child Node

As opposed to the first child, the child node that immediately precedes the
end-tag of the parent node is called the last child. To get the last child of a
node, you can access its XmlNode.LastChild property that is declared as
follows:
public virtual XmlNode LastChild{get};

The Siblings of a Node

The child nodes that are nested in a parent node and share the same level
are referred to as siblings. Consider the above file: Director, CastMembers,

C# 3.0 Practical Learning II 100


and Length are child nodes of the Video node but the Actor node is not a
child of the Video node. Consequently, Director, Actors, and Length are
siblings.

Obviously, to get a sibling, you must first have a node. To access the sibling
of a node, you can use its XmlNode.NextSibling property, which is declared
as follows:
public virtual XmlNode NextSibling{get};

C# 3.0 Practical Learning II 101


Operations on XML Elements
  

Fundamental Operations
 

Introduction

So far, to create an XML element, we were directly typing in a file. When such
a file has been created and saved, it is ready to be processed. Here is an
example of a file named Videos.xml:
<?xml version="1.0" encoding="utf-8" ?>
<Videos>
<Title>The Distinguished Gentleman</Title>
</Videos>

In some applications, you will want the user to provide you with the
necessary value(s) to create an element. Fortunately, XmlDocument, the
XmlNode, and the XmlElement classes provide all the necessary properties
and methods to perform the routine operations of an XML file, an element,
or a node. The operations include locating a node, adding a new element, or
deleting a node.

Before performing an operation, you will usually need to decide in what


section of the file you want to action to bee applied. As it happens, you have
the root node, a particular node inside the file, parent of a node, the sibling of
a node, etc. To get to a node, you will usually first get a reference to its
XmlElement. To do this, you can declare an XmlElement variable and
initialize it with that reference.

Practical Learning: Introducing operations on XML Elements

1. Start Microsoft Visual C# and create a Console Application named


CollegeParkAutoParts3

2. On the main menu, click Project -> Add New Item...

3. In the Templates list, click XML File

4. Set the Name to makes and click Add

C# 3.0 Practical Learning II 102


5. Change the file as follows:
 
<?xml version="1.0" encoding="utf-8"?>
<Makes>
<Make>Acura</Make>
<Make>Audi</Make>
<Make>BMW</Make>
<Make>Chevrolet</Make>
</Makes>

6. On the main menu, click File -> Save makes.xml As...

7. Access the main folder of the current project and, inside of it, open a
sub-folder of the same name (it should be opened already). In the sub-
folder of the same name, open the bin sub-folder followed by the
Release sub-folder. Click Save

8. In the Solution Explorer, right-click CollegeParkAutoParts2 -> Add ->


New Item...

9. In the Templates list, make sure XML File is selected.


Set the Name to models and click Add

10. To save the file, on the main menu, click File -> Save models.xml As...

11. Access the main folder of the current project and, inside of it, open a
sub-folder of the same name (it should be selected already). In the sub-
folder of the same name, open the bin sub-folder followed by the
Release sub-folder. Click Save

12. Change the file as follows:


 
<?xml version="1.0" encoding="utf-8" ?>
<Models>
<Model>NSX</Model>
<Model>TL</Model>
<Model>Spider</Model>
<Model>A4</Model>
<Model>RS6</Model>
<Model>323I</Model>
<Model>M5</Model>
<Model>Astro</Model>
<Model>Cavalier</Model>
<Model>Prot&#233;g&#233;</Model>
</Models>

Adding an Empty Element

To assist with programmatically creating a new element, the XmlDocument


class provides the CreateElement() method that is overloaded with three
versions. One of the versions uses the following syntax:

C# 3.0 Practical Learning II 103


public XmlElement CreateElement(string name);

Using this method, to create a new element, call it and pass it the name of
the element. For example, imagine you want to add a new Title element to
the above file. You would start with code as follows:

using System;

using System.IO;
using System.Xml;

namespace VideoCollection1
{
class Program
{
static int Main(string[] args)
{
string strFilename = "Videos.xml";
XmlDocument xmlDoc = new XmlDocument();

if (File.Exists(strFilename))
{
xmlDoc.Load(strFilename);

XmlElement elmNew =
xmlDoc.CreateElement("Title");
}

Console.WriteLine();
return 0;
}
}
}

In order to add the new element to the file, you must specify its position in
the tree: whether it would be the first or the last node, whether you want to
position it before or after a node of your choice. For example, if you want to
add a new Title element to the above file, it would be considered a child of
the root, that is, a child of the XmlDocument.DocumentElement property. In
the previous lesson, we learned how to get a reference to the root node.

To support the positions of existing nodes, the XmlNode class, which is the
ancestor of all XML nodes of the .NET Framework, provides various
appropriate methods. One of these methods is AppendChild(), which is used
to add an element as the last child of its parent. The syntax of the
XmlNode.AppendChild() method is:

public virtual XmlNode AppendChild(XmlNode newChild);

When calling this method, pass the XmlNode object you had previous created.
After adding the node, if you want the file to keep it, you should save it. Here
is an example:
using System;

C# 3.0 Practical Learning II 104


using System.IO;
using System.Xml;

namespace VideoCollection1
{
class Program
{
static int Main(string[] args)
{
string strFilename = "Videos.xml";
XmlDocument xmlDoc = new XmlDocument();

if (File.Exists(strFilename))
{
xmlDoc.Load(strFilename);

XmlElement elmRoot = xmlDoc.DocumentElement;


XmlElement elmNew =
xmlDoc.CreateElement("Title");
elmRoot.AppendChild(elmNew);
xmlDoc.Save(strFilename);
}

Console.WriteLine();
return 0;
}
}
}

This would produce:


<?xml version="1.0" encoding="utf-8"?>
<Videos>
<Title>The Distinguished Gentleman</Title>
<Title />
</Videos>

Notice that the newly added element is empty.

Adding an Element With Value

If you want the element to have a value, the XmlDocument class provides the
CreateTextNode() method. This method returns an XmlText value. The
syntax of this method is:
public virtual XmlText CreateTextNode(string text);

This method takes as argument the string that would constitute the value of
the element. Before calling it, you should have used the
XmlNode.AppendChild() method to create a node. Calling this method on
the LastChild node of the one that called the AppendChild() would specify
the value of the new node. Here is an example:
using System;

C# 3.0 Practical Learning II 105


using System.IO;
using System.Xml;

namespace VideoCollection1
{
class Program
{
static int Main(string[] args)
{
string strFilename = "Videos.xml";
XmlDocument xmlDoc = new XmlDocument();

if (File.Exists(strFilename))
{
xmlDoc.Load(strFilename);

XmlElement elmRoot = xmlDoc.DocumentElement;


XmlElement elmNew =
xmlDoc.CreateElement("Title");
XmlText txtVideo = xmlDoc.CreateTextNode("Basic
Instinct");
elmRoot.AppendChild(elmNew);
elmRoot.LastChild.AppendChild(txtVideo);

xmlDoc.Save(strFilename);
}

Console.WriteLine();
return 0;
}
}
}

This would produce:


<?xml version="1.0" encoding="utf-8"?>
<Videos>
<Title>The Distinguished Gentleman</Title>
<Title />
<Title>Basic Instinct</Title>
</Videos>

The combination of calls to XmlDocument.CreateElement() and


XmlDocument.CreateTextNode() allow you to create a new element that
has a value.

Consider the following file:


<?xml version="1.0" encoding="utf-8"?>
<Videos>
<Video>
<Title>The Distinguished Gentleman</Title>
</Video>
<Video>
<Title>Basic Instinct</Title>
</Video>

C# 3.0 Practical Learning II 106


</Videos>

Notice that the root, Videos, has a repetitive child named Video. This Video
child has its own child named Title. Imagine that you want to add a new
Video node that has a child. To do this, first create an empty Video node as
a child of the root. We learned earlier how to do that:
using System;
using System.IO;
using System.Xml;

namespace VideoCollection1
{
class Program
{
static int Main(string[] args)
{
string strFilename = "Videos.xml";
XmlDocument xmlDoc = new XmlDocument();

if (File.Exists(strFilename))
{
xmlDoc.Load(strFilename);

XmlElement elmRoot = xmlDoc.DocumentElement;


XmlElement elmNew =
xmlDoc.CreateElement("Video");
elmRoot.AppendChild(elmNew);
}

Console.WriteLine();
return 0;
}
}
}

After creating the new child of the root, initialize the grand child with the
desired name (the name doesn't have to be one of the existing names) and a
value (which is optional if you don't want the new node to have a value).
Once the new node is ready, append it as the last child of the root. If this
new node has a value, append its XmlText object as the LastChild of the
LastChild of the root. Here is an example of how you would do this:

using System;
using System.IO;
using System.Xml;

namespace VideoCollection1
{
class Program
{
static int Main(string[] args)
{
string strFilename = "Videos.xml";
XmlDocument xmlDoc = new XmlDocument();

C# 3.0 Practical Learning II 107


if (File.Exists(strFilename))
{
xmlDoc.Load(strFilename);

XmlElement elmRoot = xmlDoc.DocumentElement;


XmlElement elmNew =
xmlDoc.CreateElement("Video");
elmRoot.AppendChild(elmNew);

elmRoot = xmlDoc.DocumentElement;

elmNew = xmlDoc.CreateElement("Title");
XmlText txtVideo = xmlDoc.CreateTextNode("Her
Alibi");

elmRoot.LastChild.AppendChild(elmNew);

elmRoot.LastChild.LastChild.AppendChild(txtVideo);

xmlDoc.Save(strFilename);
}

Console.WriteLine();
return 0;
}
}
}

With this code you would go from this:


<?xml version="1.0" encoding="utf-8"?>
<Videos>
<Video>
<Title>The Distinguished Gentleman</Title>
</Video>
<Video>
<Title>Basic Instinct</Title>
</Video>
</Videos>

To this:
<?xml version="1.0" encoding="utf-8"?>
<Videos>
<Video>
<Title>The Distinguished Gentleman</Title>
</Video>
<Video>
<Title>Basic Instinct</Title>
</Video>
<Video>
<Title>Her Alibi</Title>
</Video>
</Videos>

C# 3.0 Practical Learning II 108


Now consider the following file:
<?xml version="1.0" encoding="utf-8"?>
<Videos>
<Video>
<Title>The Distinguished Gentleman</Title>
<Director>Jonathan Lynn</Director>
<Length>112 Minutes</Length>

<Format>DVD</Format>

<Rating>R</Rating>
</Video>
<Video>
<Title>Her Alibi</Title>
<Director>Bruce Beresford</Director>
<Length>94 Mins</Length>
<Format>DVD</Format>
<Rating>PG-13</Rating>
</Video>
</Videos>

The root, Videos, has a child named Video. The Video node has many child
nodes. By now, we know how to add a child to the root. We also saw how to
add a grand child with value to the root. To had many (grand) children to a
node, first build the node, add it to the root, then continuously add the
necessary nodes, one at a time, including its name and its optional value. This
would be done as follows:
using System;
using System.IO;
using System.Xml;

namespace VideoCollection1
{
class Program
{
static int Main(string[] args)
{
string strFilename = "Videos.xml";
XmlDocument xmlDoc = new XmlDocument();

if (File.Exists(strFilename))
{
xmlDoc.Load(strFilename);

XmlElement elmRoot = xmlDoc.DocumentElement;


XmlElement elmNew =
xmlDoc.CreateElement("Video");
elmRoot.AppendChild(elmNew);

elmRoot = xmlDoc.DocumentElement;

elmNew = xmlDoc.CreateElement("Title");

C# 3.0 Practical Learning II 109


XmlText txtVideo = xmlDoc.CreateTextNode("The
Day After Tomorrow");
elmRoot.LastChild.AppendChild(elmNew);

elmRoot.LastChild.LastChild.AppendChild(txtVideo);

elmNew = xmlDoc.CreateElement("Director");
txtVideo = xmlDoc.CreateTextNode("Roland
Emmerich");
elmRoot.LastChild.AppendChild(elmNew);

elmRoot.LastChild.LastChild.AppendChild(txtVideo);

elmNew = xmlDoc.CreateElement("Length");
txtVideo = xmlDoc.CreateTextNode("124 Minutes");
elmRoot.LastChild.AppendChild(elmNew);

elmRoot.LastChild.LastChild.AppendChild(txtVideo);

elmNew = xmlDoc.CreateElement("Format");
txtVideo = xmlDoc.CreateTextNode("DVD");
elmRoot.LastChild.AppendChild(elmNew);

elmRoot.LastChild.LastChild.AppendChild(txtVideo);

elmNew = xmlDoc.CreateElement("Rating");
txtVideo = xmlDoc.CreateTextNode("PG-13");
elmRoot.LastChild.AppendChild(elmNew);

elmRoot.LastChild.LastChild.AppendChild(txtVideo);

xmlDoc.Save(strFilename);
}

Console.WriteLine();
return 0;
}
}
}

 This would produce:


<?xml version="1.0" encoding="utf-8"?>
<Videos>
<Video>
<Title>The Distinguished Gentleman</Title>
<Director>Jonathan Lynn</Director>
<Length>112 Minutes</Length>
<Format>DVD</Format>
<Rating>R</Rating>
</Video>
<Video>
<Title>Her Alibi</Title>
<Director>Bruce Beresford</Director>
<Length>94 Mins</Length>
<Format>DVD</Format>

C# 3.0 Practical Learning II 110


<Rating>PG-13</Rating>
</Video>
<Video>
<Title>The Day After Tomorrow</Title>
<Director>Roland Emmerich</Director>
<Length>124 Minutes</Length>
<Format>DVD</Format>
<Rating>PG-13</Rating>
</Video>
</Videos>

Using the same approach, you can add children to children of children, and so
on.

Practical Learning: Programmatically Adding an Element

1. To give the user the ability to create a new car make, change the
Program.cs file as follows:
 
using System;
using System.Xml;

namespace CollegeParkAutoParts3
{
public static class Program
{
public static void CreateNewMake()
{
string strNewMake = "";

Console.Write("Enter Car Make: ");


strNewMake = Console.ReadLine();

// Open the Makes.xml file


XmlDocument docXMLFile = new XmlDocument();
docXMLFile.Load("Makes.xml");

// Get the root node so we can explore its children


XmlElement nodRoot = docXMLFile.DocumentElement;
// Store all the values of the elements in a string
string allMyChildren = nodRoot.InnerText;
// Locate the new make among the values of the
elements
int indexLookForNewMake =
allMyChildren.IndexOf(strNewMake);

// If the car make exists already, don't add it


if (indexLookForNewMake >= 0)
return;
else
{
// If the car is not in the list
// already, add it as a Make element

C# 3.0 Practical Learning II 111


XmlElement elmXML =
docXMLFile.CreateElement("Make");
// Create its value using the
// string provided by the user
XmlText txtXML =
docXMLFile.CreateTextNode(strNewMake);
// Add the new element at the end of the file
docXMLFile.DocumentElement.AppendChild(elmXML);
// Specify its text

docXMLFile.DocumentElement.LastChild.AppendChild(txtXML);

// Save the file


docXMLFile.Save("Makes.xml");
}
}

static int Main(string[] args)


{
return 0;
}
}
}

2. To give the user the ability to add a new car model, create the following
function in the file:
 
using System;
using System.Xml;

namespace CollegeParkAutoParts2
{
public static class Program
{
public static void CreateNewMake()
{
. . . No Change
}

public static void CreateNewModel()


{
string strNewModel = "";

Console.Write("Enter Car Model: ");


strNewModel = Console.ReadLine();

XmlDocument docXMLFile = new XmlDocument();


docXMLFile.Load("models.xml");

XmlElement nodRoot = docXMLFile.DocumentElement;


string allMyChildren = nodRoot.InnerText;
int indexNewModel =
allMyChildren.IndexOf(strNewModel);

if (indexNewModel >= 0)

C# 3.0 Practical Learning II 112


return;
else
{
XmlElement elmXML =
docXMLFile.CreateElement("Model");
XmlText txtXML =
docXMLFile.CreateTextNode(strNewModel);

docXMLFile.DocumentElement.AppendChild(elmXML);

docXMLFile.DocumentElement.LastChild.AppendChild(txtXML);

docXMLFile.Save("models.xml");
}
}

static int Main(string[] args)


{
return 0;
}
}
}

3. To guide the user with a menu, change the file as follows:


 
using System;
using System.Xml;

namespace CollegeParkAutoParts2
{
public static class Program
{
public static void CreateNewMake()
{
. . . No Change
}

public static void CreateNewModel()


{
. . . No Change
}

static int Main(string[] args)


{
char mnuChoice = 'q';

Console.WriteLine("=o=o=o=o=o=o=o=o=o=o=o=o=o=o=o=");
Console.WriteLine("=-= College Park Auto-Parts =-
=");

Console.WriteLine("=o=o=o=o=o=o=o=o=o=o=o=o=o=o=o=");

do
{

C# 3.0 Practical Learning II 113


try
{
Console.WriteLine("=-= Main Menu =-=");
Console.WriteLine("1 - Add New Car Make");
Console.WriteLine("2 - Add New Car Model");
Console.WriteLine("0 - Exit");
Console.Write("Your Choice: ");
mnuChoice = char.Parse(Console.ReadLine());
}
catch (FormatException)
{
Console.WriteLine("Invalid Choice");
Console.WriteLine("Please try again");
}

switch (mnuChoice)
{
case '1':
CreateNewMake();
break;
case '2':
CreateNewModel();
break;
default:
break;
}

Console.WriteLine();
} while((mnuChoice == '1') ||
(mnuChoice == '2'));

Console.WriteLine("\nThank you!");
return 0;
}
}
}

4. Execute the application and create the following elements:


 

Makes

Dodge

Ford

Honda

Toyota

Models

C# 3.0 Practical Learning II 114


A4 Quattro

Corolla

Dakota

Focus

Escort

Camry

Crown Victoria

Expedition

Integra

Neon

5. Close the DOS window

Adding a Filled Child Element

The above Videos.xml file had only one level under the root and no child
element of the root had children. Suppose you have the following version of
the file:
<?xml version="1.0" encoding="utf-8"?>
<Videos>
<Video>
<Title>The Distinguished Gentleman</Title>
<Director>Jonathan Lynn</Director>
<Length>112 Minutes</Length>
<Format>DVD</Format>
<Rating>R</Rating>
</Video>
<Video>
<Title>Her Alibi</Title>
<Director>Bruce Beresford</Director>
<Length>94 Mins</Length>
<Format>DVD</Format>

C# 3.0 Practical Learning II 115


<Rating>PG-13</Rating>
</Video>
</Videos>

Imagine that you want to add a Video element. You have a choice of adding
one, more, or all child elements of the Video node. To perform this operation,
one solution you can use is to "build" all child elements of the Video element,
then add the node as a whole. To support this technique, we saw earlier that
the XmlNode.InnerXml property comprises a node, its markup, its children
and their markup. This means that you can create the child nodes with their
markup(s) as a string and assign that string to an XmlNode.InnerXml string.
To do this, you would need the set version of the InnerXml property. It is
declared as follows:
public virtual string InnerXml{get; set;}

Here is an example that adds a complete new Video node to the above XML
file:
using System;
using System.IO;
using System.Xml;

namespace VideoCollection1
{
class Program
{
static int Main(string[] args)
{
string strFilename = "Videos.xml";
XmlDocument xmlDoc = new XmlDocument();

if (File.Exists(strFilename))
{
xmlDoc.Load(strFilename);

XmlElement elmXML =
xmlDoc.CreateElement("Video");
string strNewVideo = "<Title>Other People's
Money</Title>" +
"<Director>Alan
Brunstein</Director>" +
"<Length>114
Minutes</Length>" +
"<Format>VHS</Format>" +
"<Rating>PG-
13</Rating>";

elmXML.InnerXml = strNewVideo;
xmlDoc.DocumentElement.AppendChild(elmXML);

xmlDoc.Save("Videos.xml");
}

Console.WriteLine();

C# 3.0 Practical Learning II 116


return 0;
}
}
}

Inserting an Element
 

Locating an Element

So far, we have been adding nodes quite randomly, that is, without much
precision. In some cases, you may want to perform an operation on an
existing and particular node. For example, you may want to change the value
of a node, you may want to add a new child node to an existing node, etc.
Before taking any of these actions, you must be able to locate or identify the
desired element.

To assist you with finding a node, the XmlDocument class is equipped with
the GetElementByTagName() method which is overloaded with two versions.
One of the syntaxes used is:
public virtual XmlNodeList GetElementsByTagName(string name);

This method takes as argument a string. The string must be the Name of a
node. If at least one node that holds that name exists in the file, this method
returns a collection of the nodes with that name. If there is no node with that
name, the collection is returned empty and there is no exception.

Here is an example of calling the method:


using System;
using System.IO;
using System.Xml;

namespace VideoCollection1
{
class Program
{
static int Main(string[] args)
{
string strFilename = "Videos.xml";
XmlDocument xmlDoc = new XmlDocument();

if (File.Exists(strFilename))
{
xmlDoc.Load(strFilename);

// Get a reference to the root node


XmlElement elmRoot = xmlDoc.DocumentElement;

// Create a list of nodes whose name is Title

C# 3.0 Practical Learning II 117


XmlNodeList lstTitles =
xmlDoc.GetElementsByTagName("Title");

// Now you can check each node of the list


foreach(XmlNode node in lstTitles)
{
;
}
}

Console.WriteLine();
return 0;
}
}
}

Once you have a list of the nodes of a particular criterion, you can then act as
you see fit. For example, For example, you can look for a particular node that
holds a text of your choice. Here is an example:
using System;
using System.IO;
using System.Xml;

namespace VideoCollection1
{
class Program
{
static int Main(string[] args)
{
string strFilename = "Videos.xml";
XmlDocument xmlDoc = new XmlDocument();

if (File.Exists(strFilename))
{
xmlDoc.Load(strFilename);

// Get a reference to the root node


XmlElement elmRoot = xmlDoc.DocumentElement;
//XmlNodeList lstVideos =
xmlDoc.GetElementsByTagName("Video");

// Create a list of nodes whose name is Title


XmlNodeList lstTitles =
xmlDoc.GetElementsByTagName("Title");

// Now you can check each node of the list


foreach(XmlNode node in lstTitles)
{
if (node.InnerText == "Her Alibi")
{
;
}
}
}

C# 3.0 Practical Learning II 118


Console.WriteLine();
return 0;
}
}
}

Inserting an Element as a Last Child

Once again, consider our Videos.xml file:


<?xml version="1.0" encoding="utf-8"?>
<Videos>
<Video>
<Title>The Distinguished Gentleman</Title>
<Director>Jonathan Lynn</Director>
<Length>112 Minutes</Length>
<Format>DVD</Format>
<Rating>R</Rating>
</Video>
<Video>
<Title>Her Alibi</Title>
<Director>Bruce Beresford</Director>
<Length>94 Mins</Length>
<Format>DVD</Format>
<Rating>PG-13</Rating>
</Video>
<Video>
<Title>The Day After Tomorrow</Title>
<Director>Roland Emmerich</Director>
<Length>124 Minutes</Length>
<Format>DVD</Format>
<Rating>PG-13</Rating>
</Video>
</Videos>

Imagine you want to add a list of actors of the Her Alibi video. The first action
to take is to locate the video, which you can do by calling the
XmlDocument.GetElementsByTagName() method applied to a collection of
nodes whose names are Video. From this list of nodes, you can look for the
node whose value is "Her Alibi". Once you have found this element, get a
reference to its parent. Then add the new node as the LastChild object of
its parent. This can be done as follows:
using System;
using System.IO;
using System.Xml;

namespace VideoCollection1
{
class Program
{
static int Main(string[] args)
{
string strFilename = "Videos.xml";

C# 3.0 Practical Learning II 119


XmlDocument xmlDoc = new XmlDocument();

if (File.Exists(strFilename))
{
xmlDoc.Load(strFilename);

// Get a reference to the root node


XmlElement elmRoot = xmlDoc.DocumentElement;

// Create a list of nodes whose name is Title


XmlNodeList lstTitles =
xmlDoc.GetElementsByTagName("Title");

// visit each node named Title


foreach(XmlNode node in lstTitles)
{
// When you get to a node, look for the
element's value
// If you find an element whose value is Her
Alibi
if (node.InnerText == "Her Alibi")
{
// Create an element named Actors
XmlElement elmNew =
xmlDoc.CreateElement("Actors");
XmlNode elmParent = node.ParentNode;
// Add a new element named Actors to it
elmParent.AppendChild(elmNew);
xmlDoc.Save(strFilename);
}
}
}

Console.WriteLine();
return 0;
}
}
}

This would produce:


<?xml version="1.0" encoding="utf-8"?>
<Videos>
<Video>
<Title>The Distinguished Gentleman</Title>
<Director>Jonathan Lynn</Director>
<Length>112 Minutes</Length>
<Format>DVD</Format>
<Rating>R</Rating>
</Video>
<Video>
<Title>Her Alibi</Title>
<Director>Bruce Beresford</Director>
<Length>94 Mins</Length>
<Format>DVD</Format>
<Rating>PG-13</Rating>

C# 3.0 Practical Learning II 120


<Actors />
</Video>
<Video>
<Title>The Day After Tomorrow</Title>
<Director>Roland Emmerich</Director>
<Length>124 Minutes</Length>
<Format>DVD</Format>
<Rating>PG-13</Rating>
</Video>
</Videos>

This code creates an empty element. If you want to create an element that
includes a value, create its text and add that text as the LastChild of its
parent. Here is an example:
using System;
using System.IO;
using System.Xml;

namespace VideoCollection1
{
class Program
{
static int Main(string[] args)
{
string strFilename = "Videos.xml";
XmlDocument xmlDoc = new XmlDocument();

if (File.Exists(strFilename))
{
xmlDoc.Load(strFilename);

// Get a reference to the root node


XmlElement elmRoot = xmlDoc.DocumentElement;

// Create a list of nodes whose name is Title


XmlNodeList lstTitles =
xmlDoc.GetElementsByTagName("Title");

// visit each node named Title


foreach(XmlNode node in lstTitles)
{
// When you get to a node, look for the
element's value
// If you find an element whose value is Her
Alibi
if (node.InnerText == "The Distinguished
Gentleman")
{
// Create an element named Category
XmlElement elmNew =
xmlDoc.CreateElement("Category");
// Create the text of the new element

XmlText txtCatetory =
xmlDoc.CreateTextNode("Comedy");

C# 3.0 Practical Learning II 121


// Get a reference to the parent of the
node we have found
XmlNode elmParent = node.ParentNode;
// Add the new element to the node we
found
elmParent.AppendChild(elmNew);
// Specify the text of the new node

elmParent.LastChild.AppendChild(txtCatetory);
// Save the file
xmlDoc.Save(strFilename);
}
}
}

Console.WriteLine();
return 0;
}
}
}

This would produce:


<?xml version="1.0" encoding="utf-8"?>
<Videos>
<Video>
<Title>The Distinguished Gentleman</Title>
<Director>Jonathan Lynn</Director>
<Length>112 Minutes</Length>
<Format>DVD</Format>
<Rating>R</Rating>
<Category>Comedy</Category>
</Video>
<Video>
<Title>Her Alibi</Title>
<Director>Bruce Beresford</Director>
<Length>94 Mins</Length>
<Format>DVD</Format>
<Rating>PG-13</Rating>
</Video>
<Video>
<Title>The Day After Tomorrow</Title>
<Director>Roland Emmerich</Director>
<Length>124 Minutes</Length>
<Format>DVD</Format>
<Rating>PG-13</Rating>
</Video>
</Videos>

Using the same approach combined with what we learned about adding an
item, you can add a new element that itself has child nodes. Here is an
example:
using System;
using System.IO;
using System.Xml;

C# 3.0 Practical Learning II 122


namespace VideoCollection1
{
class Program
{
static int Main(string[] args)
{
string strFilename = "Videos.xml";
XmlDocument xmlDoc = new XmlDocument();

if (File.Exists(strFilename))
{
xmlDoc.Load(strFilename);

// Get a reference to the root node


XmlElement elmRoot = xmlDoc.DocumentElement;

// Create a list of nodes whose name is Title


XmlNodeList lstTitles =
xmlDoc.GetElementsByTagName("Title");

// visit each node named Title


foreach(XmlNode node in lstTitles)
{
// When you get to a node, look for the
element's value
// If you find an element whose value is The
Day After Tomorrow
if (node.InnerText == "The Day After
Tomorrow")
{
// Create an element named Actors
XmlElement elmNew =
xmlDoc.CreateElement("Actors");
// Get a reference to the parent of the
node we have found
XmlNode elmVideo = node.ParentNode;
// Add the new element to the node we
found
elmVideo.AppendChild(elmNew);

// Create an element as a child of the


new element
// Specify its name as Actor
elmNew = xmlDoc.CreateElement("Actor");
// Create the text of the new element
XmlText txtActor =
xmlDoc.CreateTextNode("Dennis Quaid");
// Add the new Actor element to the
Actors node
elmVideo.LastChild.AppendChild(elmNew);
// Specify the text of the new node

elmVideo.LastChild.LastChild.AppendChild(txtActor);

C# 3.0 Practical Learning II 123


// In the same way, add the other Actor
nodes
elmNew = xmlDoc.CreateElement("Actor");
txtActor = xmlDoc.CreateTextNode("Jake
Gyllenhaal");
elmVideo.LastChild.AppendChild(elmNew);

elmVideo.LastChild.LastChild.AppendChild(txtActor);

elmNew = xmlDoc.CreateElement("Actor");
txtActor = xmlDoc.CreateTextNode("Emmy
Rossum");
elmVideo.LastChild.AppendChild(elmNew);

elmVideo.LastChild.LastChild.AppendChild(txtActor);

elmNew = xmlDoc.CreateElement("Actor");
txtActor = xmlDoc.CreateTextNode("Dash
Mihok");
elmVideo.LastChild.AppendChild(elmNew);

elmVideo.LastChild.LastChild.AppendChild(txtActor);

// Save the file


xmlDoc.Save(strFilename);
}
}
}

Console.WriteLine();
return 0;
}
}
}

This would produce:


<?xml version="1.0" encoding="utf-8"?>
<Videos>
<Video>
<Title>The Distinguished Gentleman</Title>
<Director>Jonathan Lynn</Director>
<Length>112 Minutes</Length>
<Format>DVD</Format>
<Rating>R</Rating>
<Category>Comedy</Category>
</Video>
<Video>
<Title>Her Alibi</Title>
<Director>Bruce Beresford</Director>
<Length>94 Mins</Length>
<Format>DVD</Format>
<Rating>PG-13</Rating>
<Actors />
</Video>
<Video>

C# 3.0 Practical Learning II 124


<Title>The Day After Tomorrow</Title>
<Director>Roland Emmerich</Director>
<Length>124 Minutes</Length>
<Format>DVD</Format>
<Rating>PG-13</Rating>
<Actors>
<Actor>Dennis Quaid</Actor>
<Actor>Jake Gyllenhaal</Actor>
<Actor>Emmy Rossum</Actor>
<Actor>Dash Mihok</Actor>
</Actors>
</Video>
</Videos>

You can also insert one or more elements as children of an existing node after
locating that node. Here is an example:
using System;
using System.IO;
using System.Xml;

namespace VideoCollection1
{
class Program
{
static int Main(string[] args)
{
string strFilename = "Videos.xml";
XmlDocument xmlDoc = new XmlDocument();

if (File.Exists(strFilename))
{
xmlDoc.Load(strFilename);

// Get a reference to the root node


XmlElement elmRoot = xmlDoc.DocumentElement;

// Create a list of nodes whose names are Title


XmlNodeList lstTitles =
xmlDoc.GetElementsByTagName("Title");

// visit each node named Title


foreach(XmlNode node in lstTitles)
{
// When you get to a node, look for the
element's value
// If you find an element whose value is Her
Alibi
if (node.InnerText == "Her Alibi")
{
// Get a reference to the video node
that is
// the parent of the video titled Her
Alibi
XmlNode elmVideo = node.ParentNode;

C# 3.0 Practical Learning II 125


// Create a list of the child nodes of
the Her alibi video
XmlNodeList lstActors =
elmVideo.ChildNodes;

// Visit each item of the collection


// looking for an element named Actors
foreach (XmlNode nodActor in lstActors)
{
// If you find an element named
Actors
if (nodActor.Name == "Actors")
{
// Create a new element named
Actor
// Specify its name as Actor
XmlElement elmNew =
xmlDoc.CreateElement("Actor");
// Create the text of the new
element
XmlText txtActor =
xmlDoc.CreateTextNode("Tom Selleck");
// Add the new Actor element to
the Actors node

elmVideo.LastChild.AppendChild(elmNew);
// Specify the text of the new
node

elmVideo.LastChild.LastChild.AppendChild(txtActor);

// Add other Actor nodes


elmNew =
xmlDoc.CreateElement("Actor");
txtActor =
xmlDoc.CreateTextNode("Paulina Porizkova");

elmVideo.LastChild.AppendChild(elmNew);

elmVideo.LastChild.LastChild.AppendChild(txtActor);

elmNew =
xmlDoc.CreateElement("Actor");
txtActor =
xmlDoc.CreateTextNode("William Daniels");

elmVideo.LastChild.AppendChild(elmNew);

elmVideo.LastChild.LastChild.AppendChild(txtActor);

// Save the file


xmlDoc.Save(strFilename);

// Stop, in this example, we don't


expect another Actors node
break;

C# 3.0 Practical Learning II 126


}
}
}
}
}

Console.WriteLine();
return 0;
}
}
}

This would produce:


<?xml version="1.0" encoding="utf-8"?>
<Videos>
<Video>
<Title>The Distinguished Gentleman</Title>
<Director>Jonathan Lynn</Director>
<Length>112 Minutes</Length>
<Format>DVD</Format>
<Rating>R</Rating>
<Category>Comedy</Category>
</Video>
<Video>
<Title>Her Alibi</Title>
<Director>Bruce Beresford</Director>
<Length>94 Mins</Length>
<Format>DVD</Format>
<Rating>PG-13</Rating>
<Actors>
<Actor>Tom Selleck</Actor>
<Actor>Paulina Porizkova</Actor>
<Actor>William Daniels</Actor>
</Actors>
</Video>
<Video>
<Title>The Day After Tomorrow</Title>
<Director>Roland Emmerich</Director>
<Length>124 Minutes</Length>
<Format>DVD</Format>
<Rating>PG-13</Rating>
<Actors>
<Actor>Dennis Quaid</Actor>
<Actor>Jake Gyllenhaal</Actor>
<Actor>Emmy Rossum</Actor>
<Actor>Dash Mihok</Actor>
</Actors>
</Video>
</Videos>

Practical Learning: Adding Elements

C# 3.0 Practical Learning II 127


1. In the Solution Explorer, right-click CollegeParkAutoParts3 -> Add ->
New Item...

2. In the Templates list, make sure XML File is selected.


Set the Name to parts and click Add

3. Change the file as follows:


 
<?xml version="1.0" encoding="utf-8" ?>
<Parts>
<Part>
<PartNumber>293749</PartNumber>
<Make>Acura</Make>
<Model>MDX 3.5 4WD</Model>
<CarYear>2005</CarYear>
<PartName>Air Filter</PartName>
<UnitPrice>16.85</UnitPrice>
</Part>
<Part>
<PartNumber>283759</PartNumber>
<Make>Audi</Make>
<Model>A4 Quattro</Model>
<CarYear>2002</CarYear>
<PartName>Clutch Release Bearing</PartName>
<UnitPrice>55.50</UnitPrice>
</Part>
<Part>
<PartNumber>491759</PartNumber>
<Make>Dodge</Make>
<Model>Neon</Model>
<CarYear>1998</CarYear>
<PartName>Crankshaft Position Sensor</PartName>
<UnitPrice>22.85</UnitPrice>
</Part>
<Part>
<PartNumber>844509</PartNumber>
<Make>Chevrolet</Make>
<Model>Camaro</Model>
<CarYear>2000</CarYear>
<PartName>Control Module Connector</PartName>
<UnitPrice>25.65</UnitPrice>
</Part>
</Parts>

4. To save the file, on the main menu, click File -> Save parts.xml As...

5. Access the main folder of the current project and, inside of it, open a
sub-folder of the same name (you should be in that folder already). In
the sub-folder of the same name, open the bin sub-folder followed by
the Release sub-folder. Click Save

C# 3.0 Practical Learning II 128


6. To allow the user to create new parts, change the Program.cs file as
follows:
 
using System;
using System.Xml;

namespace CollegeParkAutoParts3
{
public static class Program
{
public static void CreateNewMake()
{
. . . No Change
}

public static void CreateNewModel()


{
. . . No Change
}

public static void AddNewPart()


{
int carYear;
string strMake, strModel,
strPartNumber, strPartName;
double unitPrice;

// - Generate a random number between 100000 and


999999 - //

// We will generate a random number for the item


// To start, we will use the miliseconds as a seed
int ms = DateTime.Now.Millisecond;
Random rndNumber = new Random(ms);
int next = rndNumber.Next(100000, 999999);
// Display the new number in the Part # text box
strPartNumber = next.ToString();

//// - Let the user specify the car model year


- ////
int curYear = DateTime.Now.Year + 1;

Console.WriteLine("Enter the following information "


+
"as is related to the new car
part");
Console.WriteLine("For the car model that the " +
"new part is made for, enter the
year");
Console.Write("between 1960 and " + curYear + ": ");
carYear = int.Parse(Console.ReadLine());

// - Display the list of Makes to the user to select


one - //

C# 3.0 Practical Learning II 129


// We will need a reference to the XML document

XmlDocument docXML = new XmlDocument();

// Open the Makes.xml file


docXML.Load("Makes.xml");

// Get a reference to the root node


XmlElement nodRoot = docXML.DocumentElement;
// Locate all nodes whose name is Make
XmlNodeList nodItems =
nodRoot.GetElementsByTagName("Make");
// Retrieve the value of each Make node and display
// that value to the user
Console.WriteLine("Here is a list of the car " +
"makes in our system");
for (int i = 0; i < nodItems.Count; i++)
Console.WriteLine(nodItems[i].InnerXml);
Console.Write("From this list, enter the car " +
"make of the new part: ");
strMake = Console.ReadLine();
Console.WriteLine("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
=");

// - Display the list of car Models to the


// user to select one - //
// Open the Models.xml file
docXML.Load("Models.xml");

// Get a reference to the root node


nodRoot = docXML.DocumentElement;
// Locate all nodes whose name is Model
nodItems = nodRoot.GetElementsByTagName("Model");
// Retrieve the value of each Model node and display
// that value to the user
Console.WriteLine("Here is a list of the " +
"car models in our system");
for (int i = 0; i < nodItems.Count; i++)
Console.WriteLine(nodItems[i].InnerXml);
Console.Write("From this list, enter the car " +
"model of the part: ");
strModel = Console.ReadLine();
Console.WriteLine("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
=");

//// - Request the part name - ////


Console.Write("Enter Part Name: ");
strPartName = Console.ReadLine();

//// - Request the unit price - ////


Console.Write("Enter Unit Price: ");
unitPrice = double.Parse(Console.ReadLine());

Console.WriteLine("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
=");
Console.WriteLine("New Car Part Summary");

C# 3.0 Practical Learning II 130


Console.WriteLine("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
=");
Console.WriteLine("Part #: " + strPartNumber);
Console.WriteLine("Model Year: " + carYear);
Console.WriteLine("Car Make: " + strMake);
Console.WriteLine("Car Model: " + strModel);
Console.WriteLine("Part Name: " + strPartName);
Console.WriteLine("Unit Price: " + unitPrice);
Console.WriteLine("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
=");

// XmlDocument docXML = new XmlDocument();


docXML.Load("Parts.xml");

XmlElement elmXML = docXML.CreateElement("Part");


string strNewPart = "<PartNumber>" + strPartNumber +
"</PartNumber>" +
"<CarYear>" + carYear.ToString()
+
"</CarYear>" +
"<Make>" + strMake + "</Make>" +
"<Model>" + strModel +
"</Model>" +
"<PartName>" + strPartName +
"</PartName>" + "<UnitPrice>" +
unitPrice.ToString() +
"</UnitPrice>";

elmXML.InnerXml = strNewPart;
docXML.DocumentElement.AppendChild(elmXML);

docXML.Save("Parts.xml");
}

static int Main(string[] args)


{
char mnuChoice = 'q';

Console.WriteLine("=o=o=o=o=o=o=o=o=o=o=o=o=o=o=o=");
Console.WriteLine("=-= College Park Auto-Parts =-
=");

Console.WriteLine("=o=o=o=o=o=o=o=o=o=o=o=o=o=o=o=");

do
{
try
{
Console.WriteLine("=-= Main Menu =-=");
Console.WriteLine("1 - Add New Car Make");
Console.WriteLine("2 - Add New Car Model");
Console.WriteLine("3 - Add New Part");
Console.WriteLine("0 - Exit");
Console.Write("Your Choice: ");
mnuChoice = char.Parse(Console.ReadLine());

C# 3.0 Practical Learning II 131


}
catch (FormatException)
{
Console.WriteLine("Invalid Choice");
Console.WriteLine("Please try again");
}

switch (mnuChoice)
{
case '1':
CreateNewMake();
break;
case '2':
CreateNewModel();
break;
case '3':
AddNewPart();
break;
default:
break;
}

Console.WriteLine();
} while((mnuChoice == '1') ||
(mnuChoice == '2') ||
(mnuChoice == '3') );

Console.WriteLine("\nThank you!");
return 0;
}
}
}

7. Execute the application and create the following parts:


 

Unit
Year Make Model Part Name
Price

1986 Acura Integra Alternator 110.75

1996 Dodge Neon Brake Pads 34.95

1996 Honda Civic Passenger Mirror 24.65

2002 Audi A4 Quattro Exhaust Gasket 1.55

1998 Honda Civic Brake Pads 34.85

C# 3.0 Practical Learning II 132


2004 Dodge Neon Radiator Fan Assembly 125.95

2002 Audi A4 Quattro Axle Differential Bearing - Left 10.25

2000 Ford Escort Crankshaft Position Sensor 18.65

1998 Toyota Corolla Radiator 95.95

2004 Dodge Neon Oil Pump 112.85

2004 Honda Civic Oxygen Sensor 90.55

2000 Ford Escort Right Caliper Assembly Front 32.85

2004 Dodge Neon Exhaust Valve 5.85

2002 Audi A4 Quattro Alternator 305.50

1986 Acura Integra Fuel Cap (Regular) 4.15

2004 Dodge Neon Clutch Release Bearing 25.75

2002 Dodge Dakota Starter Motor 145.95

2002 Acura NSX Oil Filter 7.05

1998 BMW 325I Rack and Pinion Bellow Kit 19.25

2001 Acura Integra Voltage Regulator 215.75

2002 Audi A4 Quattro Muffler Hanger 3.35

2002 Acura NSX Oil Drain Plug 1.35

2002 Dodge Dakota Circuit Breaker 3.25

C# 3.0 Practical Learning II 133


2004 Dodge Neon Brake Pad 20.55

2004 Honda Civic Fusible Link 3.35

2002 Dodge Dakota Circuit Breaker 3.45

2004 Honda Civic Differential Bearing 36.75

1998 Toyota Corolla Thermostat Standard Temperature 9.35

2002 Audi A4 Quattro Cooling Fan Sensor 8.65

2002 Acura NSX Oil Pump Seal 12.55

2004 Dodge Neon Master Cylinder w/o ABS w/2 Wheel 102.95

2002 Acura NSX Valve Stem Oil Seal 1.75

2002 Dodge Dakota Fuse 0.40

1998 Toyota Corolla Regular Thermostat 11.15

8. Close the DOS window

Insertion an Element Referencing a Sibling

Instead of simply adding a new node at the end of child nodes, you can
specify any other position you want. For example, you may want the new
node to precede an existing child node. To support this operation, the
XmlNode class provides the InsertBefore() method. Its syntax is:

public virtual XmlNode InsertBefore(XmlNode newChild, XmlNode


refChild);

The first argument of this method is the new node that will be added. The
second argument is the sibling that will succeed the new node. Consider the
following version of our Videos.xml file:

C# 3.0 Practical Learning II 134


<?xml version="1.0" encoding="utf-8"?>
<Videos>
<Video>
<Title>The Distinguished Gentleman</Title>
<Director>Jonathan Lynn</Director>
<Length>112 Minutes</Length>
<Format>DVD</Format>
<Rating>R</Rating>
<Category>Comedy</Category>
</Video>
<Video>
<Title>Her Alibi</Title>
<Director>Bruce Beresford</Director>
<Length>94 Mins</Length>
<Format>DVD</Format>
<Rating>PG-13</Rating>
</Video>
<Video>
<Title>Fatal Attraction</Title>
<Director>Adrian Lyne</Director>
<Length>119 Minutes</Length>
<Format>DVD</Format>
<Rating>R</Rating>
</Video>
<Video>
<Title>The Day After Tomorrow</Title>
<Director>Roland Emmerich</Director>
<Length>124 Minutes</Length>
<Format>DVD</Format>
<Rating>PG-13</Rating>
</Video>
</Videos>

Imagine you want to create a new Category element below the Director
element whose name is Adrian Lyne. You can first get a list of videos. Inside
of each video, check the nodes and find out whether the video has a Director
node whose text is Adrian Lyne. Once you find that node, you can add the
new element after it. Here is an example:
using System;
using System.IO;
using System.Xml;

namespace VideoCollection1
{
class Program
{
static int Main(string[] args)
{
string strFilename = "Videos.xml";
XmlDocument xmlDoc = new XmlDocument();

if (File.Exists(strFilename))
{
xmlDoc.Load(strFilename);

C# 3.0 Practical Learning II 135


// Get a reference to the root node
XmlElement elmRoot = xmlDoc.DocumentElement;

// Create a list of the videos


XmlNodeList lstVideos =
xmlDoc.GetElementsByTagName("Video");

// visit each video


foreach (XmlNode node in lstVideos)
{
// Within a video, create a list of its
children
XmlNodeList lstChildren = node.ChildNodes;

// Visit each child node


foreach (XmlNode dir in lstChildren)
{
// If the child node is (a director and
its name is) Adrian Lyne
if (dir.InnerText == "Adrian Lyne")
{
// Create an element named Category
XmlElement elmNew =
xmlDoc.CreateElement("Category");
// Specify the text of the new
element

elmNew.InnerText = "Drama";

// Insert the new node below the


Adrian Lyne node Director
node.InsertAfter(elmNew, dir);

// Save the file


xmlDoc.Save(strFilename);

// Stop
break;
}
}
}
}

Console.WriteLine();
return 0;
}
}
}

This would produce:


<?xml version="1.0" encoding="utf-8"?>
<Videos>
<Video>

C# 3.0 Practical Learning II 136


<Title>The Distinguished Gentleman</Title>
<Director>Jonathan Lynn</Director>
<Length>112 Minutes</Length>
<Format>DVD</Format>
<Rating>R</Rating>
<Category>Comedy</Category>
</Video>
<Video>
<Title>Her Alibi</Title>
<Director>Bruce Beresford</Director>
<Length>94 Mins</Length>
<Format>DVD</Format>
<Rating>PG-13</Rating>
</Video>
<Video>
<Title>Fatal Attraction</Title>
<Director>Adrian Lyne</Director>
<Category>Drama</Category>
<Length>119 Minutes</Length>
<Format>DVD</Format>
<Rating>R</Rating>
</Video>
<Video>
<Title>The Day After Tomorrow</Title>
<Director>Roland Emmerich</Director>
<Length>124 Minutes</Length>
<Format>DVD</Format>
<Rating>PG-13</Rating>
</Video>
</Videos>

In the same way, you can insert a new node after a child of a child (of a child
of a child of a child) of any node.

If you want to new node to be positioned after an existing child node, you
can call the XmlNode.InsertAfter() method. Its syntax is:
public virtual XmlNode InsertAfter(XmlNode newChild, XmlNode
refChild);

Node Removal

If you have a node you don't want or don't need anymore in the file, you can
delete it. To delete a node, the XmlNode class provides the RemoveChild()
method. Its syntax is:
public virtual XmlNode RemoveChild(XmlNode oldChild);

This method takes as argument the node to delete. If the node exists, it
would be deleted and the method would return it. If the node doesn't exist,
nothing would happen. To effectively use this method, you should first locate
the particular node you want to delete. You can look for it using any of the

C# 3.0 Practical Learning II 137


logics we have applied so far. Once you find the node, you can then delete it.
Imagine you want to delete a node whose name is Director and whose value
is Bruce Beresford. Here is an example of calling this method to perform the
operation:
using System;
using System.IO;
using System.Xml;

namespace VideoCollection1
{
class Program
{
static int Main(string[] args)
{
string strFilename = "Videos.xml";
XmlDocument xmlDoc = new XmlDocument();

if (File.Exists(strFilename))
{
xmlDoc.Load(strFilename);

// Get a reference to the root node


XmlElement elmRoot = xmlDoc.DocumentElement;

// Create a list of the videos


XmlNodeList lstVideos =
xmlDoc.GetElementsByTagName("Video");

// visit each video


foreach (XmlNode node in lstVideos)
{
// Within a video, create a list of its
children
XmlNodeList lstChildren = node.ChildNodes;

// Visit each child node


foreach (XmlNode dir in lstChildren)
{
// If the child node is Bruce Beresford
if (dir.InnerText == "Bruce Beresford")
{
node.RemoveChild(dir);

// Save the file


xmlDoc.Save(strFilename);

// Stop
break;
}
}
}
}

Console.WriteLine();

C# 3.0 Practical Learning II 138


return 0;
}
}
}

To delete all child nodes of a node, you can call the XmlNode.RemoveAll()
method. Its syntax is:
public virtual void RemoveAll();

When called, this method will remove all child nodes, if any, of their parent
node.

C# 3.0 Practical Learning II 139


The Attributes of an XML
Element
 

Fundamentals of Attributes
 

Introduction

When studying XML elements we saw how they constituted the main objects
of an XML document. We also saw that an element could be nested inside of
another element. Instead of nesting an element, you can transform the
nested element into being part of the nesting element and thereby giving
away its element qualities. This is the basis of an attribute.

An attribute is a value that is created as part of an element, making that


value different from the value of a regular element. There are similarities and
differences between an element and an attribute.

The element and the attribute have these in common:

 Both (must) have a name

 Each may or may not have a value

The differences between an element and an attribute are:

 An attribute is considered a characteristic of an element. This means that


an attribute belongs to an element

 An element can have one or more attributes. An attribute cannot have


an element

 An attribute must be created in the start-tag of an element

 An element cannot be defined as part of an attribute. That is, an


attribute is subject to an element and an attribute doesn't own the
attribute

Practical Learning: Introducing Attributes 

1. Create a new Console Application named CountriesStatistics1

C# 3.0 Practical Learning II 140


2. To save the file, on the Standard toolbar, click the Save All button

3. Accept all defaults and click Save

4. In the Solution Explorer, right-click CountriesStatistics1 -> Add -> New


Item...

5. In the Templates list, click XML File

6. Set the Name to continents and click Add

7. Change the file as follows:


 
<?xml version="1.0" encoding="utf-8" ?>
<World>
</World>

8. To save the file, on the main menu, click File -> Save continents.xml
As...

9. Access the main folder of the current project and, inside of it, open a
sub-folder of the same name (you should be in that folder already). In
the sub-folder of the same name, open the bin sub-folder followed by
the Release sub-folder. Click Save

Creating an Attribute

An attribute must be created inside the start-tag of an element. To manually


create an attribute, type the left angle bracket of the element, followed by the
name of the element, an empty space, and the name of the attribute. The
name follows the same rules we defined for names in XML.

An attribute should have a value that can be used to distinguish it. To specify
the name of an attribute, assign a value as a string to its name. Imagine you
have an ISBN element as a child of a Video element as follows:
<Video>
<ISBN>0-7888-1623-3</ISBN>
</Video>

In this case, since ISBN is simply a child of the Video element, you can
change the ISBN element to become an attribute of the Video element as
follows:
<Video ISBN="0-7888-1623-3">

Now, ISBN is an attribute of the Video element.

Operations on an XML Attribute


 

C# 3.0 Practical Learning II 141


Introduction

In the .NET Framework, an attribute is represented by the XmlAttribute


class. Like all nodes, this class is based on the XmlNode class. The name of an
attribute is represented by its (read-only) Name property. The value of an
attribute is represented by its Value property . Besides Value, you can also
use XmlAttribute.InnerText or XmlAttribute.InnerXml to access the
text of an attribute.

Manually Creating an Attribute

An element can have 0, one, or more attributes. The attributes of an element


are stored in the Attributes property of an XmlElement object. The
XmlElement.Attributes property is based on a class called
XmlAttributeCollection. The XmlAttributeCollection class is based on
the XmlNamedNodeMap class.

Before performing an attribute-related operation on an element, to find out


whether the element has any attribute, you can check the value of the
Boolean HasAttributes property of its XmlElement element. If this property
produces a true value, then the element has at least one attribute; otherwise,
the element doesn't have any.

While a certain element may have an attribute, a sibling element with the
same name may not have an attribute or may have a completely different
type of attribute. Here is an XML file with attributes in some elements:
<?xml version="1.0" encoding="utf-8" ?>
<Videos>
<Video ISBN="0-7888-1623-3">
<Title Screenplay="Marty Kaplan">The Distinguished
Gentleman</Title>
<Director>Jonathan Lynn</Director>
<Actors>
</Actors>
<Length>112 Minutes</Length>

<Format>DVD</Format>

<Rating>R</Rating>
</Video>
<Video>
<Title WrittenBy="Charlie Peter">Her Alibi</Title>
<Director>Bruce Beresford</Director>
<Length>94 Mins</Length>
<Format>DVD</Format>
<Rating>PG-13</Rating>
</Video>
</Videos>

C# 3.0 Practical Learning II 142


Remember that you can include white spaces to make your code easy to
read. This means that you can type an attribute on the next line of its
element's name. In the Lesson 36, we saw that every element must be
closed. We saw that we could close an element with an end-tag as follows:
<Video><ISBN>0-7888-1623-3</ISBN></Video>

We also saw that we could close an element locally as follows: <Video />. If
you create an attribute in an empty element, you can also close it by typing
the indicative forward slash before the right angle bracket and after an empty
space. Here is an example:
<Video ISBN="0-7888-1623-3" />

Practical Learning: Creating Simple Attributes 

1. Change the file continents.xml file as follows:


 
<?xml version="1.0" encoding="utf-8" ?>
<World>
<Continent Name="Africa"></Continent>
<Continent Name="Europe"></Continent>
<Continent Name="Asia"></Continent>
<Continent Name="South America"></Continent>
</World>

2. Save the file

Programmatically Creating an Attribute 

As mentioned already, an attribute primarily belongs to an element. This


means that, when creating an attribute, you must specify what element it
would belong to. To support the attributes of an element, the XmlElement
class is equipped with the SetAttribute() method which is overloaded in
two versions. The first version of this method uses the following syntax:
public virtual void SetAttribute(string name, string value);

The first argument is the name of the new attribute and the second argument
will be its text. Before adding an attribute, you should first identify its parent
element. Here is an example that adds an attribute to the root element:

using System;

using System.IO;
using System.Xml;

namespace VideoCollection
{
public static class Exercise
{

C# 3.0 Practical Learning II 143


private static void CreateAttribute()
{
string strFilename = "Videos.xml";
XmlDocument docXML = new XmlDocument();

if (File.Exists(strFilename))
{
// Open the XML file
docXML.Load(strFilename);

// Create an attribute and add it to the root


element
docXML.DocumentElement.SetAttribute("FileDesc",
"Personal Video Collection");
docXML.Save("Videos.xml");
}
}

static int Main(string[] args)


{
CreateAttribute();
return 0;
}
}
}

From the above Videos.xml file, this code would result in:
<?xml version="1.0" encoding="utf-8"?>
<Videos FileDesc="Personal Video Collection">
<Video ISBN="0-7888-1623-3">
<Title Screenplay="Marty Kaplan">The Distinguished
Gentleman</Title>
<Director>Jonathan Lynn</Director>
<Actors>
</Actors>
<Length>112 Minutes</Length>
<Format>DVD</Format>
<Rating>R</Rating>
</Video>
<Video>
<Title WrittenBy="Charlie Peter">Her Alibi</Title>
<Director>Bruce Beresford</Director>
<Length>94 Mins</Length>
<Format>DVD</Format>
<Rating>PG-13</Rating>
</Video>
</Videos>

To support attribute addition, the XmlDocument class is equipped with the


CreateAttribute() method, which is overloaded in three versions. The first
version of this method has the following syntax:
public XmlAttribute CreateAttribute(string name);

C# 3.0 Practical Learning II 144


This method expects the name of the attribute as argument. If it succeeds,
this method produces an XmlAttribute object. To add the new attribute to
an element, you can call the XmlElement.SetAttributeNote() method.
This method is overloaded in two versions. One of the versions uses the
following syntax:
public virtual XmlAttribute SetAttributeNode(XmlAttribute
newAttr);

This method expects an XmlAttribute object. Here is an example that looks


for a particular video in a collection and adds an ISBN attribute to it:
using System;
using System.IO;
using System.Xml;

namespace VideoCollection
{
public static class Exercise
{
private static void CreateAttribute()
{
string strFilename = "Videos.xml";
XmlDocument docXML = new XmlDocument();

if (File.Exists(strFilename))
{
// Open the XML file
docXML.Load(strFilename);

// Create a new attribute


XmlAttribute atrXML =
docXML.CreateAttribute("ISBN");
atrXML.Value = "0-7907-3900-3";

// Get a list of elements whose names are Video


XmlNodeList nodVideos =
docXML.GetElementsByTagName("Video");
// Since we will look for a specific video, get
the list of all titles
XmlNodeList nodTitles =
docXML.GetElementsByTagName("Title");

// Visit each title


for (int i = 0; i < nodTitles.Count; i++)
{
// Look for a video whose title is "Her
Alibi"
if (nodTitles[i].InnerText.Equals("Her
Alibi"))
{
// Once you find that video, add the new
attribute to it
((XmlElement)
(nodVideos[i])).SetAttributeNode(atrXML);

C# 3.0 Practical Learning II 145


}
}

docXML.Save("Videos.xml");
}
}

static int Main(string[] args)


{
CreateAttribute();
return 0;
}
}
}

From the above Videos.xml file, this code would result in:
<?xml version="1.0" encoding="utf-8"?>
<Videos FileDesc="Personal Video Collection">
<Video ISBN="0-7888-1623-3">
<Title Screenplay="Marty Kaplan">The Distinguished
Gentleman</Title>
<Director>Jonathan Lynn</Director>
<Actors>
</Actors>
<Length>112 Minutes</Length>
<Format>DVD</Format>
<Rating>R</Rating>
</Video>
<Video ISBN="0-7907-3900-3">
<Title WrittenBy="Charlie Peter">Her Alibi</Title>
<Director>Bruce Beresford</Director>
<Length>94 Mins</Length>
<Format>DVD</Format>
<Rating>PG-13</Rating>
</Video>
</Videos>

Practical Learning: Creating an Attribute

1. Create a new function as follows:


 
using System;
using System.IO;
using System.Xml;

namespace CountriesStatistics1
{
public static class Program
{
private static void CreateContinent()
{

C# 3.0 Practical Learning II 146


string strFilename = "continents.xml";
XmlDocument xmlDocContinents = new XmlDocument();
FileStream fsStatistics = null;

if (File.Exists(strFilename))
{
string strContinent = null;

try
{
fsStatistics = new FileStream(strFilename,
FileMode.Open,

FileAccess.Read);
// Open the XML file
xmlDocContinents.Load(fsStatistics);
}
finally
{
fsStatistics.Close();
}

// Request the name of a continent from the user

Console.Write("Enter the name of a continent:


");
strContinent = Console.ReadLine();

// Create an element that the new attribute will


be added to
XmlElement xmlNewContinent =

xmlDocContinents.CreateElement("Continent");

// Create a Continent element and set its value


to
// that of the new continent
xmlNewContinent.SetAttribute("Name",
strContinent);

// Add the element and its attribute to the


document

xmlDocContinents.DocumentElement.AppendChild(xmlNewContinent);

// Save the XML file


xmlDocContinents.Save("continents.xml");
}
}

static int Main(string[] args)


{
CreateContinent();
return 0;
}

C# 3.0 Practical Learning II 147


}
}

2. Execute the application and create a continent. Here is an example:


 
Enter the name of a continent: North America
Press any key to continue . . .

3. Close the DOS window


 
<?xml version="1.0" encoding="utf-8"?>
<World>
<Continent Name="Africa">
</Continent>
<Continent Name="Europe">
</Continent>
<Continent Name="Asia">
</Continent>
<Continent Name="South America">
</Continent>
<Continent Name="North America" />
</World>

The Parent of an Attribute

Once an attribute has been created, to identify the element it belongs to, you
can access its XmlAttribute.OwnerElement property. This property
produces an XmlElement value.

Attribute Removal

If an element has an attribute you don't want or that you don't need
anymore, you can delete that attribute. You have various options, two are
available through the XmlElement class.

The attributes of an XmlElement object are considered stored in an indexed


list with the most left attribute at index 0, the second from left at index 1, and
so on. Based on this, to remove an attribute by locating it based on its index,
you can call the XmlElement.RemoveAt() method. Its syntax is:
public virtual XmlNode RemoveAttributeAt(int i);

When calling this method, if an attribute exists at position i, it will be deleted


and the method would return it. If there is no attribute at that index, the
method doesn't do anything and it returns 0.

Using the XmlElement.RemoveAt() method to delete an attribute can be


uncertain because you would not know whether there is an attribute at the
specified position. An alternative is to specify the name of the attribute you

C# 3.0 Practical Learning II 148


want to delete. To support this, the XmlElement class is equipped with the
RemoveAttribute() method, which is overloaded with two versions. One of
the versions of this method uses the following syntax:
public virtual void RemoveAttribute(string name);

This method expects as argument the name of the attribute to remove.

Another technique you can use consists of defining an XmlAttribute object


and submitting to its XmlElement parent to delete. To do this, you can call
the RemoveAttributeNode() method of the XmlElement object. Its syntax
is:
public virtual XmlAttribute RemoveAttributeNode(XmlAttribute
oldAttr);

When calling this method, pass the attribute object as argument. If the
attribute exists, it would be removed and the method would return the
deleted attribute. If the attribute doesn't exist, nothing would happen.

The Collection of Attributes of an Element


 

Introduction

So far, we have used only one attribute per element. Fortunately, you can
create as many attributes as you judge necessary in an element. To do this,
type the name of each attribute, assign it a double-quoted string and
separate the attribute from the next with an empty space. Here is an example
of an element with different attributes:
<Video ISBN="0-7888-1623-3" ScreenRatio="Standard"
SoundtrackAvailable="True" />

As mentioned already and as you should always remember, attributes belong


to an element. To support them, the attributes of an element are stored in
the Attributes property of the XmlElement class. The
XmlElement.Attributes property is based on a class called
XmlAttributeCollection. The XmlAttributeCollection class is based on
the XmlNamedNodeMap class. This class lays a foundation to access attributes
using their names or index in the collection.

To know the number of attributes in an element, you can use the


XmlNamedNodeMap.Count property.

Practical Learning: Adding Attributes

1. Create a new Console Application named CountriesStatistics2

2. To save the project, on the Standard toolbar, click the Save All button

C# 3.0 Practical Learning II 149


3. Accept all defaults and click Save

4. In the Solution Explorer, right-click CountriesStatistics2 -> Add -> New


Item...

5. In the Templates list, make sure XML File is selected.


Set the Name to continents and click Add

6. Change the file as follows:


 
<?xml version="1.0" encoding="utf-8" ?>
<World Area="510,072,000,000"
Population="6,379,157,361">
<Continent Name="Africa"
Area="30,065,000"
Population="807,419,000">
<Country CountryName="Burundi"
Area="27,830"
Population="6,231,221"
Capital="Bujumbura" Code="bi" />
</Continent>
<Continent Name="Europe"
Area="9,938,000"
Population="730,916,000">
<Country CountryName="Italy"
Area="301,230"
Population="58,057,477"
Capital="Rome" Code="it" />
</Continent>
</World>

7. To save the file, on the main menu, click File -> Save continents.xml
As...

8. Access the main folder of the current project and, inside of it, open a
sub-folder of the same name (you should be in that folder already). In
the sub-folder of the same name, open the bin sub-folder followed by
the Release sub-folder. Click Save

Access to an Attribute

To access an attribute by its position in the collection, you can use the
XmlNamedNodeMap.Item() method.

The XmlAttributeCollection class is equipped with an ItemOf indexed


property. This property is overloaded in three versions. The first version has
the following syntax:
public virtual XmlAttribute this[int i] {get;}

This property allows you to access an attribute by considering that the


attributes are stored in an array. The first or most left attribute has an index

C# 3.0 Practical Learning II 150


of 0; the second attribute from left (of course without counting the name of
the element) has an index of 1, and so on.

It can be difficult and sometimes unpredictable, in some scenarios, to access


an attribute by its index because you must know exactly where each attribute
is positioned. Consider the following version of our Videos.xml XML file:
<?xml version="1.0" encoding="utf-8" ?>
<Videos FileDesc="Personal Video Collection">
<Video ISBN="0-7888-1623-3"
ScreenRatio="Standard"
SoundtrackAvailable="True">
<Title StoryBy="Marty Kaplan and Jonathan Reynold"
Screenplay="Marty Kaplan">The Distinguished
Gentleman</Title>
<Director>Jonathan Lynn</Director>
<Actors></Actors>
<Length>112 Minutes</Length>
<Format>DVD</Format>
<Rating>R</Rating>
</Video>
<Video ISBN="0-7907-3900-3">
<Title Screenplay="Charlie Peter">Her Alibi</Title>
<Director>Bruce Beresford</Director>
<Length>94 Mins</Length>
<Format>DVD</Format>
<Rating>PG-13</Rating>
</Video>
</Videos>

In the first video, the name of the screenplay writer is stored at index 1. In
the second video, the name of the screenplay writer is stored at index 0. In
this case, it may not be a good item to use the index to locate an attribute.
Fortunately, the second version of the overloaded
XmlAttributeCollection.ItemOf[] property has the following syntax:

public virtual XmlAttribute this[string name] {get;}

With this version, you can explicitly specify the name of the attribute that you
want.

Practical Learning: Accessing an Attribute

1. To display the continents, change the code as follows:


 
using System;
using System.IO;
using System.Xml;

namespace CountriesStatistics2
{
public static class Program
{

C# 3.0 Practical Learning II 151


private static void ShowContinents()
{
string strFilename = "continents.xml";
XmlDocument xmlWorldStats = new XmlDocument();
FileStream fsWorldStats = null;

if (File.Exists(strFilename))
{
string strContinent = null;

try
{
fsWorldStats = new FileStream(strFilename,
FileMode.Open,

FileAccess.Read);
// Open the XML file
xmlWorldStats.Load(fsWorldStats);
}
finally
{
fsWorldStats.Close();
}

// Get a list of elements whose names are


Continent
XmlNodeList lstContinents =

xmlWorldStats.GetElementsByTagName("Continent");

// Show the statistics on the continents


Console.WriteLine(" =-= Continents =-=");
Console.WriteLine("Name\tArea\t\tPopulation");

foreach(XmlNode attr in lstContinents)


{
Console.WriteLine("{0}\t{1}\t{2}",
attr.Attributes["Name"].InnerText,
attr.Attributes["Area"].InnerText,

attr.Attributes["Population"].InnerText);
}
}
}

public static int Main(string[] args)


{
ShowContinents();
return 0;
}
}
}

2. Execute the application to see the result:


 

C# 3.0 Practical Learning II 152


=-= Continents =-=
Name Area Population
Africa 30,065,000 807,419,000
Europe 9,938,000 730,916,000

3. Close the DOS window

Attribute Addition

Whether using its index or name, after accessing an attribute, you can
manipulate it as you see fit. For example, you can change or delete it using
the same techniques we saw to perform on an individual attribute.

As mentioned already, the attributes are stored as a list. Because you have
complete access to this list and the positions of its attributes, when creating
or adding a new attribute, you can specify the position the new attribute
should have in the collection. To create an attribute as the first in an element,
you can call the XmlAttributeCollection.Prepend() method. Its syntax
is:
public virtual XmlAttribute Prepend(XmlAttribute node);

Another technique you can use consists of locating an attribute first. Once
you have one, to create a new attribute before it, you can call the
XmlAttributeCollection.InsertBefore() method. Its syntax is:

public virtual XmlAttribute InsertBefore(XmlAttribute newNode,


XmlAttribute refNode);

To add a new attribute after the current one, you can call the
XmlAttributeCollection.InsertAfter() method. Its syntax is:

public virtual XmlAttribute InsertAfter(XmlAttribute newNode,


XmlAttribute refNode);

To add an attribute at the end of the list of attributes of an element, you can
call the XmlAttributeCollection.Append() method. Its syntax is:
public virtual XmlAttribute Append(XmlAttribute node);

Practical Learning: Creating Attributes

1. To allow the user to create a new continent, change the program as


follows:
 
using System;
using System.IO;
using System.Xml;

namespace CountriesStatistics2
{

C# 3.0 Practical Learning II 153


public static class Program
{
private static void ShowContinents()
{
string strFilename = "continents.xml";
XmlDocument xmlWorldStats = new XmlDocument();
FileStream fsWorldStats = null;

if (File.Exists(strFilename))
{
try
{
fsWorldStats = new FileStream(strFilename,
FileMode.Open,

FileAccess.Read);
// Open the XML file
xmlWorldStats.Load(fsWorldStats);
}
finally
{
fsWorldStats.Close();
}

// Get a list of elements whose names are


Continent
XmlNodeList lstContinents =

xmlWorldStats.GetElementsByTagName("Continent");

// Show the statistics on the continents

Console.WriteLine("\n===================================");
Console.WriteLine(" =-= Continents =-=");

Console.WriteLine("===================================");
Console.WriteLine("Name\tArea\t\tPopulation");

Console.WriteLine("===================================");
foreach (XmlNode attr in lstContinents)
{
Console.WriteLine("{0}\t{1}\t{2}",
attr.Attributes["Name"].InnerText,
attr.Attributes["Area"].InnerText,

attr.Attributes["Population"].InnerText);

Console.WriteLine("-----------------------------------");
}
}
}

private static void CreateNewContinent()


{

C# 3.0 Practical Learning II 154


string strContinent = null;
string strArea = null;
string strPopulation = null;

// Open the XML file


XmlDocument xmlDocContinents = new XmlDocument();

string strFilename = "continents.xml";

FileStream fsContinents = null;

if (File.Exists(strFilename))
{
try
{
fsContinents = new FileStream(strFilename,
FileMode.Open,

FileAccess.Read);
// Open the XML file
xmlDocContinents.Load(fsContinents);
}
finally
{
fsContinents.Close();
}
}

// Create a Continent element that the new attribute


will be added to
XmlElement xmlNewContinent =
xmlDocContinents.CreateElement("Continent");

// Present the current list of continents to the


user
ShowContinents();

// Request the name of a continent from the user


Console.Write("Enter a new continent: ");
strContinent = Console.ReadLine();

// Create a Name attribute using the continent that


the user entered
xmlNewContinent.SetAttribute("Name", strContinent);

// Request the continent's area from the user


Console.Write("Enter the area of the continent: ");
strArea = Console.ReadLine();

// Create the Area attribute


xmlNewContinent.SetAttribute("Area", strArea);

// Request the population of the continent from the


user
Console.Write("Enter the population of the
continent: ");

C# 3.0 Practical Learning II 155


strPopulation = Console.ReadLine();

// Create the Population attribute


xmlNewContinent.SetAttribute("Population",
strPopulation);

// Add the element and its attribute to the document

xmlDocContinents.DocumentElement.AppendChild(xmlNewContinent);

// Save the XML file


xmlDocContinents.Save(strFilename);
ShowContinents();
}

public static int Main(string[] args)


{
int choice = 0;

Console.WriteLine(" =-= Main Menu =-=");


Console.WriteLine("0 - Quit");
Console.WriteLine("1 - Display Continents");
Console.WriteLine("2 - Create New Continent");
Console.Write("Your Choice? ");
choice = int.Parse(Console.ReadLine());

switch (choice)
{
case 1:
ShowContinents();
break;
case 2:
CreateNewContinent();
break;
}

Console.WriteLine();
return 0;
}
}
}

2. Execute the application to test it. Here is an example:


 
=-= Main Menu =-=
0 - Quit
1 - Display Continents
2 - Create New Continent
Your Choice? 2

===================================
=-= Continents =-=
===================================
Name Area Population
===================================

C# 3.0 Practical Learning II 156


Africa 30,065,000 807,419,000
-----------------------------------
Europe 9,938,000 730,916,000
-----------------------------------
Enter a new continent: North America
Enter the area of the continent: 24490000
Enter the population of the continent: 514600000

===================================
=-= Continents =-=
===================================
Name Area Population
===================================
Africa 30,065,000 807,419,000
-----------------------------------
Europe 9,938,000 730,916,000
-----------------------------------
North America 24490000 514600000
-----------------------------------

Press any key to continue . . .

3. Close the DOS window


 
<?xml version="1.0" encoding="utf-8"?>
<World Area="510,072,000,000" Population="6,379,157,361">
<Continent Name="Africa"
Area="30,065,000"
Population="807,419,000">
<Country CountryName="Burundi"
Area="27,830"
Population="6,231,221"
Capital="Bujumbura"
Code="bi" />
</Continent>
<Continent Name="Europe"
Area="9,938,000"
Population="730,916,000">
<Country CountryName="Italy"
Area="301,230"
Population="58,057,477"
Capital="Rome"
Code="it" />
</Continent>
<Continent Name="North America"
Area="24490000"
Population="514600000" />
</World>

4. To allow the user to create a new country, change the file as follows:
 
using System;
using System.IO;
using System.Xml;

C# 3.0 Practical Learning II 157


namespace CountriesStatistics2
{
public static class Program
{
private static void ShowContinents()
{
string strFilename = "continents.xml";
XmlDocument xmlWorldStats = new XmlDocument();
FileStream fsWorldStats = null;

if (File.Exists(strFilename))
{
try
{
fsWorldStats = new FileStream(strFilename,
FileMode.Open,

FileAccess.Read);
// Open the XML file
xmlWorldStats.Load(fsWorldStats);
}
finally
{
fsWorldStats.Close();
}

// Get a list of elements whose names are


Continent
XmlNodeList lstContinents =

xmlWorldStats.GetElementsByTagName("Continent");

// Show the statistics on the continents

Console.WriteLine("\n===================================");
Console.WriteLine(" =-= Continents =-=");

Console.WriteLine("===================================");
Console.WriteLine("Name\tArea\t\tPopulation");

Console.WriteLine("===================================");
foreach (XmlNode attr in lstContinents)
{
Console.WriteLine("{0}\t{1}\t{2}",
attr.Attributes["Name"].InnerText,
attr.Attributes["Area"].InnerText,

attr.Attributes["Population"].InnerText);

Console.WriteLine("-----------------------------------");
}
}
}

C# 3.0 Practical Learning II 158


private static void CreateNewContinent()
{
string strContinent = null;
string strArea = null;
string strPopulation = null;

// Open the XML file


XmlDocument xmlDocContinents = new XmlDocument();

string strFilename = "continents.xml";

FileStream fsContinents = null;

if (File.Exists(strFilename))
{
try
{
fsContinents = new FileStream(strFilename,
FileMode.Open,

FileAccess.Read);
// Open the XML file
xmlDocContinents.Load(fsContinents);
}
finally
{
fsContinents.Close();
}
}

// Create a Continent element that the new attribute


will be added to
XmlElement xmlNewContinent =
xmlDocContinents.CreateElement("Continent");

// Present the current list of continents to the


user
ShowContinents();

// Request the name of a continent from the user


Console.Write("Enter a new continent: ");
strContinent = Console.ReadLine();

// Create a Name attribute using the continent that


the user entered
xmlNewContinent.SetAttribute("Name", strContinent);

// Request the continent's area from the user


Console.Write("Enter the area of the continent: ");
strArea = Console.ReadLine();

// Create the Area attribute


xmlNewContinent.SetAttribute("Area", strArea);

// Request the population of the continent from the


user

C# 3.0 Practical Learning II 159


Console.Write("Enter the population of the
continent: ");
strPopulation = Console.ReadLine();

// Create the Population attribute


xmlNewContinent.SetAttribute("Population",
strPopulation);

// Add the element and its attribute to the document

xmlDocContinents.DocumentElement.AppendChild(xmlNewContinent);

// Save the XML file


xmlDocContinents.Save(strFilename);
ShowContinents();
}

private static void AddCountry()


{
string strContinent = null;
string strCountry = null;
string strArea = null;
string strPopulation = null;
string strCapital = null;
string strCode = null;
string strFilename = "continents.xml";

// Open the XML file


XmlDocument xmlDocContinents = new XmlDocument();
FileStream fsContinents = null;

if (File.Exists(strFilename))
{
try
{
fsContinents = new FileStream(strFilename,
FileMode.Open,

FileAccess.Read);
// Open the XML file
xmlDocContinents.Load(fsContinents);
}
finally
{
fsContinents.Close();
}
}

// Display the list of continents to the user


Console.WriteLine("Here is a list of the created
continents");
ShowContinents();

// Request a continent from the user


Console.Write("Enter the desired continent: ");
strContinent = Console.ReadLine();

C# 3.0 Practical Learning II 160


// Get a list of elements whose names are Continent
XmlNodeList lstContinents =

xmlDocContinents.GetElementsByTagName("Continent");

// Visit each Continent element


for (int i = 0; i < lstContinents.Count; i++)
{
// Get a list of the attributes of the current
element
XmlAttributeCollection curAttributes =
lstContinents[i].Attributes;

// Check each attribute, looking for


// the continent that the user entered
for (int j = 0; j < curAttributes.Count; j++)
{
// Check if the current continent
// is the same that the user selected
if (curAttributes["Name"].InnerText ==
strContinent)
{
// Once you find one, get its XmlElement
reference
XmlElement elmNewCountry =

xmlDocContinents.CreateElement("Country");

// Request the name of a country from


the user
Console.Write("Enter the name of the
country: ");
strCountry = Console.ReadLine();
// Create the country specified by the
user

elmNewCountry.SetAttribute("CountryName", strCountry);

// Request the area of the country from


the user
Console.Write("Enter the area of the
country: ");
strArea = Console.ReadLine();
// Create the Area specified by the user
elmNewCountry.SetAttribute("Area",
strArea);

// Request the population of the country


from the user
Console.Write("Enter the population of
the country: ");
strPopulation = Console.ReadLine();
// Create the Population attribute
elmNewCountry.SetAttribute("Population",
strPopulation);

C# 3.0 Practical Learning II 161


// Request the Capital of the country
from the user
Console.Write("Enter the capital of the
country: ");
strCapital = Console.ReadLine();
// Create the Capital attribute
elmNewCountry.SetAttribute("Capital",
strCapital);

// Request the Internet Code of the


country from the user

Console.Write("Enter the Internet Code of


the country: ");
strCode = Console.ReadLine();
// Create the Internet Code attribute
elmNewCountry.SetAttribute("Code",
strCode);

// Add the element (and its attribute)


as
// a child of the current Continent

lstContinents[i].AppendChild(elmNewCountry);

// Save the XML file


xmlDocContinents.Save("Countries.xml");

break;
}
}
}
}

public static int Main(string[] args)


{
int choice = 0;

do
{
Console.WriteLine(" =-= Main Menu =-=");
Console.WriteLine("1 - Display Continents");
Console.WriteLine("2 - Create New Continent");
Console.WriteLine("3 - Create New Country");
Console.WriteLine("0 - Quit");
Console.Write("Your Choice? ");
choice = int.Parse(Console.ReadLine());

switch (choice)
{
case 1:
ShowContinents();
break;

C# 3.0 Practical Learning II 162


case 2:
CreateNewContinent();
break;
case 3:
AddCountry();
break;
default:
break;
}
} while ((choice == 1) ||
(choice == 2) ||
(choice == 3));

Console.WriteLine();
return 0;
}
}
}

5. Execute the application to test it. Here is an example:


 
=-= Main Menu =-=
1 - Display Continents
2 - Create New Continent
3 - Create New Country
0 - Quit
Your Choice? 2

===================================
=-= Continents =-=
===================================
Name Area Population
===================================
Africa 30,065,000 807,419,000
-----------------------------------
Europe 9,938,000 730,916,000
-----------------------------------
North America 24490000 514600000
-----------------------------------
Enter a new continent: Asia
Enter the area of the continent: 43810582
Enter the population of the continent: 3902404193

===================================
=-= Continents =-=
===================================
Name Area Population
===================================
Africa 30,065,000 807,419,000
-----------------------------------
Europe 9,938,000 730,916,000
-----------------------------------
North America 24490000 514600000
-----------------------------------
Asia 43810582 3902404193

C# 3.0 Practical Learning II 163


-----------------------------------
=-= Main Menu =-=
1 - Display Continents
2 - Create New Continent
3 - Create New Country
0 - Quit
Your Choice? 3
Here is a list of the created continents

===================================
=-= Continents =-=
===================================
Name Area Population
===================================
Africa 30,065,000 807,419,000
-----------------------------------
Europe 9,938,000 730,916,000
-----------------------------------
North America 24490000 514600000
-----------------------------------
Asia 43810582 3902404193
-----------------------------------
Enter the desired continent: Europe
Enter the name of the country: Italy
Enter the area of the country: 301230
Enter the population of the country: 58751711
Enter the capital of the country: Rome
Enter the Internet code of the country: it
=-= Main Menu =-=
1 - Display Continents
2 - Create New Continent
3 - Create New Country
0 - Quit
Your Choice? 0

Press any key to continue . . .

6. Close the DOS window


 
<?xml version="1.0" encoding="utf-8"?>
<World Area="510,072,000,000" Population="6,379,157,361">
<Continent Name="Africa"
Area="30,065,000"
Population="807,419,000">
<Country CountryName="Burundi"
Area="27,830"
Population="6,231,221"
Capital="Bujumbura" Code="bi" />
</Continent>
<Continent Name="Europe"
Area="9,938,000"
Population="730,916,000">
<Country CountryName="Italy"
Area="301,230"
Population="58,057,477"

C# 3.0 Practical Learning II 164


Capital="Rome"
Code="it" />
</Continent>
<Continent Name="North America"
Area="24490000"
Population="514600000" />
<Continent Name="Asia"
Area="43810582"
Population="3902404193" />
</World>

Attribute Removal

Using the list of attributes of an element, you can delete one or all attributes
of an element. Since the attributes are stored in a collection, you can locate
the undesired attribute by its index and then delete it. To do this, you can call
the XmlAttributeCollection.RemoveAt() method. Its syntax is:
public virtual XmlAttribute RemoveAt(int i);

This method expects the index of the attribute that needs to be removed. As
mentioned for the XmlAttributeCollection.ItemOf indexed property, to
efficiently use this RemoveAt() method, you should know the exact index of
the attribute, otherwise, you may access and therefore delete the wrong
attribute. An alternative is to explicitly identify the attribute you want to
delete. To do this, you can call the XmlAttributeCollection.Remove()
method. Its syntax is:
public virtual XmlAttribute Remove(XmlAttribute node);

This method takes as attribute the XmlAttribute identification of the


attribute you want to remove.

To delete all attributes of an element, you can call the


XmlAttributeCollection.RemoveAll() method. Its syntax is:

public virtual void RemoveAll();

This method would simply remove all attributes that belong to an


XmlElement object.

C# 3.0 Practical Learning II 165


Characteristics of XML
Nodes
 

Overview of Types of Nodes


 

Introduction

To differentiate the various nodes that belong to an XML file, they are
classified by their category. As mentioned earlier, the types of node are listed
in the XmlNodeType enumerator.

Comments

A comment is a character, a line or a paragraph that is not considered as part


of the XML code that needs to be processed. A comment allows you to insert
notes or personal observations inside an XML file. For this reason, a
commented section can be written any way you like. This means that a
comment can include plain text, formulas, expressions, or even XML code as
long as you know that that XML code will not be validated: it will ignored by
the parser.

To create a comment, you use the following formula:


<!-- Blah Blah Blah ->

Between <!-- and -., any text in that section is considered a comment and
you can include anything you want. Both sections of the comment use two
dashes, not more, not less. Here is an example:
<?xml version="1.0" encoding="utf-8"?>
<Videos>
<Video>
<!-- In this collection, we will keep each title "as i"
-.
<Title>The Distinguished Gentleman</Title>
<Director>Jonathan Lynn</Director>
<Length>112 Minutes</Length>
<Format>DVD</Format>
<Rating>R</Rating>
</Video>

C# 3.0 Practical Learning II 166


<Video>
<Title>Her Alibi</Title>
<Director>Bruce Beresford</Director>
<Length>94 Mins</Length>
<Format>DVD</Format>
<Rating>PG-13</Rating>
</Video>
</Videos>

This would produce:

The System.Xml represents a comment through the XmlComment class. Like


any other part of an XML file, a comment is represented by the
XmlComment.Name property. This allows you to retrieve the name of a
comment that is included in the document.

To create a comment, you can call the XmlDocument.CreateComment()


method. Its syntax is:

public virtual XmlComment CreateComment(string data);

C# 3.0 Practical Learning II 167


This method takes as argument the text that would go into the commented
section. After calling it, if the method succeeds, which it usually does, it
returns the XmlComment object that was created.

CDATA

Except for comments, the parser is used to "scan" the whole XML file to
analyze it. Every tag is then interpreted. As we mentioned already, the value
of each tag can be displayed in a browser between its opening and its
closing tag, and the browser uses different font styles to make a distinction.
When creating some tags and some sections of the file, you may want the
parser to consider those particular tags and sections as regular text. That is,
you may want the parser to treat a certain tag and its value as if it were
regular text even though it is created as an XML file.

To prevent the parser from interpreting a tag regularly but to treat that tag
and its value as regular text, you can create it in a CDATA section. To do this,
create a section that starts with <![CDATA[, followed by anything you want,
and ending with ]]>. The formula used is:
<![CDATA[ Blah Blah Blah ]]>

Between <![CDATA[ and ]]>, you can type anything, including one or more
normal XML tags. Here is an example:
<?xml version="1.0" encoding="utf-8"?>
<Videos>
<![CDATA[<VideoCollection>Personal Collection of
Movies</VideoCollection>]]>
<Video>
<Title>The Distinguished Gentleman</Title>
<Director>Jonathan Lynn</Director>
<Length>112 Minutes</Length>
<Format>DVD</Format>
<Rating>R</Rating>
</Video>
<Video>
<Title>Her Alibi</Title>
<Director>Bruce Beresford</Director>
<Length>94 Mins</Length>
<Format>DVD</Format>
<Rating>PG-13</Rating>
</Video>
</Videos>

C# 3.0 Practical Learning II 168


The .NET Framework supports the creation of a CDATA section through the
XmlCDataSection class. This class is equipped with a Name property that
allows you t retrieve the name of a CDATA section in an XmlDocument object.

To programmatically create a
CDATA section, you can call the
XmlDocument.CreateCDataSection() method. Its syntax is:

public virtual XmlCDataSection CreateCDataSection(string data);

This method receives the content of the CDATA section as argument. If the
method succeeds, which it usually does, it returns an XmlCDataSection
value.

XML Serialization

Thanks to its flexibility and platform independent way of dealing with values,
XML is always a prima candidate for value serialization. Unlike strict object
serialization, but like the techniques of file processing we reviewed earlier,
XML considers the value members of an object, such as its fields and
properties, for serialization. This means that XML doesn't allow serializing an

C# 3.0 Practical Learning II 169


object as its own value, but you can implement an effective object
serialization by the way you proceed.

C# 3.0 Practical Learning II 170


Introduction to Data Sets
and Tables
 

A Set of Data
 

Introduction

A database is a list of items. The nature of the items is not particularly


important because any list of any type of items constitutes a database. The
idea of considering it a database is for better organization and management.
This means that, traditionally, the database word suggests that the list must
be formally created in human memory, on a piece of paper, or on a computer
file, etc. Any type of thing can be made into a list. This means that one list
can be made of people. Another list can be made of CDs. Another list can be
made of countries, and so on. Because of this, before creating a list, you
should first plan it by deciding what kinds of items would compose the list.

An item that is part of a list is called datum, with the plural being data, but
data is also used for singular. The group of items, or data, that makes up a
list is referred to as a set of data.

   

Data Set Creation

To support the creation and management of a set of data, the .NET


Framework provides the DataSet class, which is defined in the System.Data
namespace. Therefore, to create a list, you can start by declaring a variable
of type DataSet. To initialize a DataSet variable, the class is equipped with
three constructors, the first of which is the default, meaning it doesn't take
any argument. The DataSet default constructor allows you to declare a
variable without providing further information, just to let the compiler know
that you are going to create or need a list of items. Here is an example:
using System;
using System.Data;

public class VideoCollection

C# 3.0 Practical Learning II 171


{
public VideoCollection()
{
DataSet dsVideoCollection = new DataSet();
}
}

If you are planning to use a DataSet object from more than one method or
event, you can declare it globally, that is, in the class of a form. Here is an
example:
using System;
using System.Data;

public class VideoCollection


{
public DataSet dsVideoCollection;

public VideoCollection()
{
dsVideoCollection = new DataSet();
}
}

When creating a set of data, you can name it. This would allow you to refer
to the list later on by its formal name. To create such a set, you can use the
second constructor whose syntax is:
public DataSet(string dataSetName);

This constructor takes as argument the formal name of the set. The name
can be anything but it must respect the rules of names of the C++ language.
Here is an example:
using System;
using System.Data;

public class VideoCollection


{
public DataSet dsVideoCollection;

public VideoCollection()
{
dsVideoCollection = new DataSet("Videos");
}
}

The third constructor is not used in your applications.

The name of the DataSet variable, in this case dsVideoCollection, is a


Windows name that will allow the operating system to identify the DataSet.
That name is required as is the case for every variable you declare. The
DataSetName name is optional but is useful in many methods as we will see.

C# 3.0 Practical Learning II 172


If you don't specify it, the compiler would generate a default name for the
DataSet object.

Tables Fundamentals
 

Introduction to Tables

Imagine you have a list of movie directors and you want to group their names
into a list. Here is an example:

Rob Reiner, Jonathan Lynn, Bruce Beresford, Jonathan Demme, Adrian Lyne

This is a one-dimensional list like a simple array. While working on this list,
you may decide to create a video collection and make the above items into a
formal list. A typical movie provides such information as its length, its rating,
the year it was released, etc. To create such a list, you would group items by
categories. One category may contain the titles of the videos. Another
category may contain the names of the directors, and so on.
To better organize a list, you may create each category, then enter the value of
each category that corresponds to a particular video. Here is an example:

Video Title Director © Year Length Format Rating

138
A Few Good Men Rob Reiner 1992 VHS R
Minutes

The Distinguished 112


Jonathan Lynn   DVD R
Gentleman Minutes

Joel Coen & Ethan 104


The Lady Killers   DVD R
Coen Minutes

120
Fatal Attraction Adrian Lyne 1987 VHS R
Minutes

Her Alibi Bruce Beresford 1989 94 Minutes DVD PG-13

129
The Manchurian Candidate Jonathan Demme 2004 DVD R
Minutes

C# 3.0 Practical Learning II 173


This type of list is called a table: A table is a two-dimensional list that contains
one or different categories of items and each category is represented with a
particular value. A category of values is called a column. Under each
category, you may have a group of values that belong to the same entry.
Such a group of values is called a row or a record. In the above table, the
values "A Few Good Men", "Rob Reiner", "1992", "138 Minute", "VH", and "R"
constitute one row or record.

Practical Learning: Introducing Tables

1. Start Microsoft Visual C# and create a Console Application named


VideoCollection1

2. To create a new class, in the Solution Explorer, right-click


VideoCollection1 -> Add -> Class...

3. Set the Name to Video and press Enter

4. Change the file as follows:


 
using System;
using System.Data;

namespace VideoCollection1
{
public class Video
{
public DataSet dsVideoCollection;

public Video()
{
dsVideoCollection = new DataSet("Videos");
}
}
}

Creating a Table

To support the creation and management of a table, the .NET Framework


provides the DataTable class that is defined in the System.Data namespace.
There are various ways you can create a table. You can declare a variable of
type DataTable. To initialize the variable, the DataTable class is equipped
with three constructors. The default constructor allows you to create a table
without giving more details, especially without formally naming it. Here is an
example:
using System;
using System.Data;

public class VideoCollection

C# 3.0 Practical Learning II 174


{
public DataSet dsVideoCollection;

public VideoCollection()
{
dsVideoCollection = new DataSet("Videos");

DataTable tblDirectors = new DataTable();


}
}

If you are planning to refer to the table from more than one method, you
should declare it globally. Here is an example:
using System;
using System.Data;

public class VideoCollection


{
public DataTable tblDirectors;
public DataSet dsVideoCollection;

public VideoCollection()
{
dsVideoCollection = new DataSet("Videos");

tblDirectors = new DataTable();


}
}

The name of the DataTable variable is required when creating a table. This
name will be used by you and the compiler to identify the table. In some
cases, you may want the table to hold an object name that you would want
to use later as we will see with some methods. To provide a formal name to a
table when creating it, you can use the second constructor of the DataTable
class. Its syntax is:
public DataTable(string tableName);

This constructor expects as argument a string that would constitute the


object name of the table. Here is an example:
using System;
using System.Data;

public class VideoCollection


{
public DataTable tblDirectors;
public DataTable tblVideoCategories;
public DataSet dsVideoCollection;

public VideoCollection()
{
dsVideoCollection = new DataSet("Videos");

C# 3.0 Practical Learning II 175


tblDirectors = new DataTable();
tblVideoCategories = new DataTable("Categories");
}
}

If you have already declared a DataTable variable using either of both


constructors and decide to specify or change its name, you can assign a
string to the DataTable.TableName property. Here is an example:
using System;
using System.Data;

public class VideoCollection


{
public DataTable tblDirectors;
public DataTable tblVideoCategories;
public DataSet dsVideoCollection;

public VideoCollection()
{
dsVideoCollection = new DataSet("Videos");

tblDirectors = new DataTable();


tblDirectors.TableName = "Directors";
tblVideoCategories = new DataTable("Categories");
}
}

The TableName name is primarily optional but it is used by various methods


as we will see. If you don't provide it, for example if you declare a DataTable
variable using the default constructor and don't specify its name through the
DataTable.TableName property, the compiler would generate a default
name for the table, such as Table1, Table2, and so on. In the same way, you
can create as many tables as you judge necessary for your application and as
we will see when moving on.

After creating a table, you can add it to a DataSet object.

The Tables of a Data Set


 

Introduction

The tables that belong to a DataSet object are stored in a property called
Tables. The DataSet.Tables property is an object of type
DataTableCollection. The DataTableCollection is a class that provides
everything you need to add, locate, or manage any table that belongs to a
DataSet object.

Accessing a Table in the Collection

C# 3.0 Practical Learning II 176


The DataTableCollection class implements the GetEnumerator() method
of the IEnumerable interface. This allows you to use a foreach loop to visit
each member table of the collection. Once you have reached a table in the
collection, you can access any of its public properties or methods. Here is an
example of applying foreach on a collection of tables of a data set to list their
names:
using System;
using System.Data;

public class VideoCollection


{
public DataTable tblActors;
public DataTable tblFormats;
public DataTable tblRatings;
public DataTable tblDirectors;
public DataTable tblVideoCategories;
public DataSet dsVideoCollection;

public VideoCollection()
{
dsVideoCollection = new DataSet("Videos");

tblDirectors = new DataTable();


tblDirectors.TableName = "Directors";
dsVideoCollection.Tables.Add(tblDirectors);

tblVideoCategories = new DataTable("Categories");


dsVideoCollection.Tables.Add(tblVideoCategories);

tblRatings = dsVideoCollection.Tables.Add("Ratings");

tblActors = dsVideoCollection.Tables.Add("Actors");
tblFormats = dsVideoCollection.Tables.Add("Formats");
}

public void ShowTables()


{
DataTableCollection tables =
this.dsVideoCollection.Tables;

foreach (DataTable tbl in tables)


Console.WriteLine("Table Name: {0}", tbl.TableName);
}
}

public static class Program


{
static int Main(string[] args)
{
VideoCollection coll = new VideoCollection();

coll.ShowTables();
Console.WriteLine();
return 0;

C# 3.0 Practical Learning II 177


}
}

This would produce:


Table Name: Directors
Table Name: Categories
Table Name: Ratings
Table Name: Actors
Table Name: Formats

Press any key to continue . . .

You can use this approach to identity a table and then perform a desired
operation on it.

Adding a New Table to a Collection

Using the DataSet.Tables property, to add a created table to a DataSet


object, call one of the Add() methods of the DataTableCollection class.
The first version of this method has the following syntax:
public virtual DataTable Add();

This method can be used to add a new table that uses the default name.
Here is an example:
using System;
using System.Data;

public class VideoCollection


{
public DataTable tblRatings;
public DataTable tblDirectors;
public DataTable tblVideoCategories;
public DataSet dsVideoCollection;

public VideoCollection()
{
dsVideoCollection = new DataSet("Videos");

tblDirectors = new DataTable();


tblDirectors.TableName = "Directors";
tblVideoCategories = new DataTable("Categories");

tblRatings = dsVideoCollection.Tables.Add();
}
}

If this is the first table added to the collection, it would be named Table1. The
second version of the DataTableCollection.Add() method uses the
following syntax:
public virtual void Add(DataTable table);

C# 3.0 Practical Learning II 178


This version allows you to add a predefined or declared DataTable object.
Here is an example:
using System;
using System.Data;

public class VideoCollection


{
public DataTable tblRatings;
public DataTable tblDirectors;
public DataTable tblVideoCategories;
public DataSet dsVideoCollection;

public VideoCollection()
{
dsVideoCollection = new DataSet("Videos");

tblDirectors = new DataTable();


tblDirectors.TableName = "Directors";
dsVideoCollection.Tables.Add(tblDirectors);

tblVideoCategories = new DataTable("Categories");


dsVideoCollection.Tables.Add(tblVideoCategories);

tblRatings = dsVideoCollection.Tables.Add();
}
}

This second version of the method requires that you create a DataTable
object first and the table probably has a name. Alternatively, if you want to
add a table using its formal name, you can use the third version of this
method. Its syntax is:
public virtual DataTable Add(string name);

This version works like the first except that, instead of the default name (such
as Table1, Table2, etc), it lets you specify the desired name of the new table.
Here are examples:
using System;
using System.Data;

public class VideoCollection


{
public DataTable tblActors;
public DataTable tblFormats;
public DataTable tblRatings;
public DataTable tblDirectors;
public DataTable tblVideoCategories;
public DataSet dsVideoCollection;

public VideoCollection()
{
dsVideoCollection = new DataSet("Videos");

C# 3.0 Practical Learning II 179


tblDirectors = new DataTable();
tblDirectors.TableName = "Directors";
dsVideoCollection.Tables.Add(tblDirectors);

tblVideoCategories = new DataTable("Categories");


dsVideoCollection.Tables.Add(tblVideoCategories);

tblRatings = dsVideoCollection.Tables.Add();

tblActors = dsVideoCollection.Tables.Add("Actors");
tblFormats = dsVideoCollection.Tables.Add("Formats");
}
}

Creating a Range of Tables

Instead of adding one table at a time, you can create a list of tables and then
add it to the DataSet.Tables collection. To support this operation, the
DataTableCollection is equipped with the AddRange() method. Its syntax
is:
public void AddRange(DataTable[] tables);

This method expects an array of DataTable objects as argument. Here is an


example:
using System;
using System.Data;

public class BookCollection


{
private void Create()
{
DataSet dsBooks = new DataSet("Book");

DataTable dtCategories = new DataTable("Categorie");


DataTable dtAuthors = new DataTable("Author");
DataTable dtPublishers = new DataTable("Publisher");
DataTable dtBooks = new DataTable("Book");

DataTable[] colTables = { dtCategories, dtAuthors,


dtPublishers, dtBooks };
dsBooks.Tables.AddRange(colTables);
}
}

Practical Learning: Creating Tables

 To create tables, change the file as follows:


 
using System;
using System.Data;

C# 3.0 Practical Learning II 180


namespace VideoCollection1
{
public class Video
{
public DataSet dsVideoCollection;

public DataTable tblVideoCategories;


public DataTable tblDirectors;
public DataTable tblRatings;
public DataTable tblActors;
public DataTable tblFormats;

public Video()
{
dsVideoCollection = new DataSet("Videos");

tblDirectors = new DataTable();


tblDirectors.TableName = "Directors";
dsVideoCollection.Tables.Add(tblDirectors);

tblVideoCategories = new DataTable("Categories");


dsVideoCollection.Tables.Add(tblVideoCategories);

tblRatings =
dsVideoCollection.Tables.Add("Ratings");

tblActors = dsVideoCollection.Tables.Add("Actors");
tblFormats =
dsVideoCollection.Tables.Add("Formats");
}
}
}

Locating a Table in a Collection

After creating the tables that are part of an application, before performing
any operation on a table, you must first retrieve its reference. This can be
done by locating the particular desired table from the collection.

To locate a table in the DataSet.Tables collection, the


DataTableCollection class is equipped with the Item property in two
versions. To locate a table using its name, use the following version of this
property:
public DataTable this[string name] {get;}

To use this property, enter the object name of the table in the square
brackets of the DataTableCollection[] property. Here is an example:
using System;
using System.Data;

public class VideoCollection

C# 3.0 Practical Learning II 181


{
public DataTable tblActors;
public DataTable tblFormats;
public DataTable tblRatings;
public DataTable tblDirectors;
public DataTable tblVideoCategories;
public DataSet dsVideoCollection;

public VideoCollection()
{
dsVideoCollection = new DataSet("Videos");

tblDirectors = new DataTable();


tblDirectors.TableName = "Directors";
dsVideoCollection.Tables.Add(tblDirectors);

tblVideoCategories = new DataTable("Categories");


dsVideoCollection.Tables.Add(tblVideoCategories);

tblRatings = dsVideoCollection.Tables.Add();

tblActors = dsVideoCollection.Tables.Add("Actors");
tblFormats = dsVideoCollection.Tables.Add("Formats");
}
}

public static class Program


{
static int Main(string[] args)
{
VideoCollection coll = new VideoCollection();

DataTable tbl =
coll.dsVideoCollection.Tables["Directors"];

Console.WriteLine("Table Name: {0}", tbl.TableName);


return 0;
}
}

This would produce:


Table Name: Directors
Press any key to continue . . .

Instead of locating a table by its name, you can use its index from the
collection. To do this, you can use the second version of the
DataTableCollection[] property. Its syntax is:

public DataTable this[int index] {get;}

This property expects as argument the index of the table in the


DataSet.Tables collection. Here is an example:

using System;
using System.Data;

C# 3.0 Practical Learning II 182


public class VideoCollection
{
public DataTable tblActors;
public DataTable tblFormats;
public DataTable tblRatings;
public DataTable tblDirectors;
public DataTable tblVideoCategories;
public DataSet dsVideoCollection;

public VideoCollection()
{
dsVideoCollection = new DataSet("Videos");

tblDirectors = new DataTable();


tblDirectors.TableName = "Directors";
dsVideoCollection.Tables.Add(tblDirectors);

tblVideoCategories = new DataTable("Categories");


dsVideoCollection.Tables.Add(tblVideoCategories);

tblRatings = dsVideoCollection.Tables.Add();

tblActors = dsVideoCollection.Tables.Add("Actors");
tblFormats = dsVideoCollection.Tables.Add("Formats");
}
}

public static class Program


{
static int Main(string[] args)
{
VideoCollection coll = new VideoCollection();

DataTable tbl = coll.dsVideoCollection.Tables[3];

Console.WriteLine("Table Name: {0}", tbl.TableName);


return 0;
}
}

This would produce:


Table Name: Actors
Press any key to continue . . .

If you provide an index below or beyond the number of tables in the set, the
compiler would throw an IndexOutOfRangeException exception. To avoid
this, you can request the index of the table. To do this, call the
DataTableCollection.IndexOf() method. It is overloaded in two versions.
One of the versions takes as argument the variable name of the table. The
syntax of this method is:
public virtual int IndexOf(DataTable table);

C# 3.0 Practical Learning II 183


Here is an example of calling this method:
using System;
using System.Data;

public class VideoCollection


{
public DataTable tblActors;
public DataTable tblFormats;
public DataTable tblRatings;
public DataTable tblDirectors;
public DataTable tblVideoCategories;
public DataSet dsVideoCollection;

public VideoCollection()
{
dsVideoCollection = new DataSet("Videos");

tblDirectors = new DataTable();


tblDirectors.TableName = "Directors";
dsVideoCollection.Tables.Add(tblDirectors);

tblVideoCategories = new DataTable("Categories");


dsVideoCollection.Tables.Add(tblVideoCategories);

tblRatings = dsVideoCollection.Tables.Add();

tblActors = dsVideoCollection.Tables.Add("Actors");
tblFormats = dsVideoCollection.Tables.Add("Formats");
}

public void LocateTable()


{
int index = dsVideoCollection.Tables.IndexOf(tblActors);
Console.WriteLine("Table Index: {0}", index.ToString());
}
}

public static class Program


{
static int Main(string[] args)
{
VideoCollection coll = new VideoCollection();

coll.LocateTable();
return 0;
}
}

This would produce:


Table Index: 3
Press any key to continue . . .

Instead of using the variable name of the table, you can locate it using its
formal name. To do this, call the following version of the IndexOf() method:

C# 3.0 Practical Learning II 184


public virtual int IndexOf(string tableName);

When the tables of a DataSet have been created, you can get their list as an
array using the DataTableCollection.List property. This property returns
an ArrayList type of list.

Instead of directly locating a table, you may be interested to know whether a


particular table exists in the DataSet.Tables collection. To check this, you
can call the DataTableCollection.Contains() method. Its syntax is:
public bool Contains(string name);

This method expects the object name of a table as argument. If the table
exists in the collection, this method returns true. Here is an example:
using System;
using System.Data;

public class VideoCollection


{
public DataTable tblActors;
public DataTable tblFormats;
public DataTable tblRatings;
public DataTable tblDirectors;
public DataTable tblVideoCategories;
public DataSet dsVideoCollection;

public VideoCollection()
{
dsVideoCollection = new DataSet("Videos");

tblDirectors = new DataTable();


tblDirectors.TableName = "Directors";
dsVideoCollection.Tables.Add(tblDirectors);

tblVideoCategories = new DataTable("Categories");


dsVideoCollection.Tables.Add(tblVideoCategories);

tblRatings = dsVideoCollection.Tables.Add();

tblActors = dsVideoCollection.Tables.Add("Actors");
tblFormats = dsVideoCollection.Tables.Add("Formats");
}
}

public static class Program


{
static int Main(string[] args)
{
VideoCollection coll = new VideoCollection();

if( coll.dsVideoCollection.Tables.Contains("Actors") )
Console.WriteLine("The Actors table exists");
else

C# 3.0 Practical Learning II 185


Console.WriteLine("The Actors table does not
exist");

Console.WriteLine();

if
(coll.dsVideoCollection.Tables.Contains("VideoTypes"))
Console.WriteLine("The VideoTypes table exists");
else
Console.WriteLine("The VideoTypes table does not
exist");

Console.WriteLine();
return 0;
}
}

This would produce:


The Actors table exists

The VideoTypes table does not exist

Press any key to continue . . .

Practical Learning: Showing Tables

1. To show a list of the tables in the DataSet object, change the Video.cs
file as follows:
 
using System;
using System.Data;

namespace VideoCollection1
{
public class Video
{
public DataSet dsVideoCollection;

public DataTable tblVideoCategories;


public DataTable tblDirectors;
public DataTable tblRatings;
public DataTable tblActors;
public DataTable tblFormats;

public Video()
{
dsVideoCollection = new DataSet("Videos");

tblDirectors = new DataTable();


tblDirectors.TableName = "Directors";
dsVideoCollection.Tables.Add(tblDirectors);

tblVideoCategories = new DataTable("Categories");

C# 3.0 Practical Learning II 186


dsVideoCollection.Tables.Add(tblVideoCategories);

tblRatings =
dsVideoCollection.Tables.Add("Ratings");

tblActors = dsVideoCollection.Tables.Add("Actors");
tblFormats =
dsVideoCollection.Tables.Add("Formats");
}

public void ShowTables()


{
int i = 1;

Console.WriteLine("Video Collection - Tables");


foreach (DataTable tbl in dsVideoCollection.Tables)
Console.WriteLine("{0}. {1}", i++,
tbl.TableName);
}
}
}

2. Access the Program.cs file and change it as follows:


 
using System;

namespace VideoCollection1
{
class Program
{
static int Main(string[] args)
{
Video vdo = new Video();

vdo.ShowTables();
Console.WriteLine();

return 0;
}
}
}

3. Execute the application:


 
Video Collection - Tables
1. Directors
2. Categories
3. Ratings
4. Actors
5. Formats

Press any key to continue . . .

4. Close the DOS window

C# 3.0 Practical Learning II 187


Tables Maintenance
 

Deleting a Table

If you happen to have a table you don't need anymore or whose role is
undefined in your application, you can delete that table. This operation is
supported by the DataTableCollection.Remove() method that is
overloaded with two versions. To delete a table using its variable declared
name, you can use the following version:
public void Remove(DataTable table);

This version expects the name that was used to declare the DataTable
object. If the table exists in the DateSet.Tables collection, it would be
deleted. Here is an example:
using System;
using System.Data;

public class VideoCollection


{
. . . No Change

public void ShowTables()


{
DataTableCollection tables =
this.dsVideoCollection.Tables;

foreach (DataTable tbl in tables)


Console.WriteLine("Table Name: {0}", tbl.TableName);

dsVideoCollection.Tables.Remove(tblVideoCategories);

Console.WriteLine();

foreach (DataTable tbl in tables)


Console.WriteLine("Table Name: {0}", tbl.TableName);
}
}

public static class Program


{
static int Main(string[] args)
{
VideoCollection coll = new VideoCollection();

coll.ShowTables();
Console.WriteLine();
return 0;
}
}

C# 3.0 Practical Learning II 188


To delete a table using its object name, you can use the following version of
the DataTableCollection.Remove() method:
public void Remove(string name);

This method expects the formal name of the table as argument. If a table
exists under that name, it would be deleted. Here is an example:
using System;
using System.Data;

public class VideoCollection


{
. . . No Change

public void ShowTables()


{
DataTableCollection tables =
this.dsVideoCollection.Tables;

foreach (DataTable tbl in tables)


Console.WriteLine("Table Name: {0}", tbl.TableName);

dsVideoCollection.Tables.Remove("Categories");

Console.WriteLine();

foreach (DataTable tbl in tables)


Console.WriteLine("Table Name: {0}", tbl.TableName);
}
}

public static class Program


{
static int Main(string[] args)
{
VideoCollection coll = new VideoCollection();

coll.ShowTables();
Console.WriteLine();
return 0;
}
}

This would produce:


Table Name: Directors
Table Name: Categories
Table Name: Ratings
Table Name: Actors
Table Name: Formats

Table Name: Directors


Table Name: Ratings
Table Name: Actors
Table Name: Formats

C# 3.0 Practical Learning II 189


Press any key to continue . . .

If no table with the name is found, the compiler would throw an


ArgumentException exception. Once again, you should first check that a
table with the undesired name exist before deleting it.

If the table exists in the collection, it may not allow the user to delete it. To
find out whether a table can be deleted, call the
DataTableCollection.CanRemove() method. Its syntax is:

public bool CanRemove(DataTable table);

Checking the Existence of a Table in a Collection

When calling the DataTableCollection.Remove() method, if the


DataTable object passed as argument is not found, the compiler would
throw either an ArgumentNullException or an ArgumentException
exceptions. For this reason, before deleting a table, you should first check its
existence. To do this, you can call the DataTableCollection.Contains()
method.

Here is an example of calling this method before deleting a table:


using System;
using System.Data;

namespace VideoCollection1
{
public class Video
{
public DataSet dsVideoCollection;

public DataTable tblVideoCategories;


public DataTable tblDirectors;
public DataTable tblRatings;
public DataTable tblActors;
public DataTable tblFormats;

public Video()
{
dsVideoCollection = new DataSet("Videos");

tblDirectors = new DataTable();


tblDirectors.TableName = "Directors";
dsVideoCollection.Tables.Add(tblDirectors);

tblVideoCategories = new DataTable("Categories");


dsVideoCollection.Tables.Add(tblVideoCategories);

tblRatings =
dsVideoCollection.Tables.Add("Ratings");

C# 3.0 Practical Learning II 190


tblActors = dsVideoCollection.Tables.Add("Actors");
tblFormats =
dsVideoCollection.Tables.Add("Formats");
}

public void ShowTables()


{
int i = 1;

Console.WriteLine("Video Collection - Tables");


foreach (DataTable tbl in dsVideoCollection.Tables)
Console.WriteLine("{0}. {1}", i++,
tbl.TableName);
}
public void DeleteTable(string name)
{
if (dsVideoCollection.Tables.Contains(name))
dsVideoCollection.Tables.Remove(name);
else
Console.WriteLine("Table {0} not found in the
database", name);
}

public void PerformMaintenance()


{
ShowTables();
Console.WriteLine();

DeleteTable("Ratings");
Console.WriteLine();

ShowTables();
Console.WriteLine();

DeleteTable("Types");
Console.WriteLine();

ShowTables();
Console.WriteLine();
}
}
}

This would produce:


Video Collection - Tables
1. Directors
2. Categories
3. Ratings
4. Actors
5. Formats

Video Collection - Tables


1. Directors
2. Categories
3. Actors

C# 3.0 Practical Learning II 191


4. Formats

Table Types not found in the database

Video Collection - Tables


1. Directors
2. Categories
3. Actors
4. Formats

Press any key to continue . . .

Clearing a Collection of Tables

To delete all tables of a object, you


DataSet can call the
DataTableCollection.Clear() method. Its syntax is:

public void Clear();

Calling this method would remove all DataTable objects of the DataSet.

C# 3.0 Practical Learning II 192


The Columns of a Table
 

Fundamentals of Columns of a Table


 

Introduction

A column is a technique of categorizing some values that belong to a table.


Based on this, one category from a list of a video application can be made
of video titles. Another category can contain the years the videos were
released. Yet another category can contain a number used to identify the
format of the video. Here is an example of a table:

Video Title Director © Year Length Format Rating

138
A Few Good Men Rob Reiner 1992 1 R
Minutes

The Distinguished 112


Jonathan Lynn   2 R
Gentleman Minutes

Joel Coen & Ethan 104


The Lady Killers   2 R
Coen Minutes

120
Fatal Attraction Adrian Lyne 1987 1 R
Minutes

Her Alibi Bruce Beresford 1989 94 Minutes 2 PG-13

129
The Manchurian Candidate Jonathan Demme 2004 2 R
Minutes

A category of information of a table is called a column. The string on top of


each column allows the user to identify what that column is used for. That
string is called the column header.

C# 3.0 Practical Learning II 193


To support the columns of a table, the .NET Framework provides the
DataColumn class.

Practical Learning: Introducing Columns

1. Start Microsoft Visual C# and create a Console Application named


VideoCollection2

2. To create a new class, in the Class View, right-click VideoCollection2 ->


Add -> Class...

3. Set the Name to Video and press Enter

4. Change the file as follows:


 
using System;

using System.Data;

namespace VideoCollection2
{
public class Video
{
private DataSet dsVideoCollection;

private DataTable tblActors;


private DataTable tblVideos;

public Video()
{
dsVideoCollection = new DataSet("VideoCollection");

tblActors = new DataTable("Actors");


dsVideoCollection.Tables.Add(tblActors);

tblVideos = new DataTable("Videos");


dsVideoCollection.Tables.Add(tblVideos);
}

public void ShowTables()


{
int i = 1;

Console.WriteLine("Video Collection - Tables");


foreach (DataTable tbl in dsVideoCollection.Tables)
Console.WriteLine("{0}. {1}", i++,
tbl.TableName);
}
}
}

C# 3.0 Practical Learning II 194


5. Access the Program.cs file and change it as follows:
 

using System;

namespace VideoCollection2
{
public class Program
{
static int Main(string[] args)
{
Video vdo = new Video();
vdo.ShowTables();

return 0;
}
}
}

6. To save the file, on the Standard toolbar, click the Save All button

7. Accepts all defaults and click Save

8. Execute the application to make sure it is working fine:


 
Video Collection - Tables
1. Actors
2. Videos
Press any key to continue . . .

9. Close the DOS window

Creating a Column

To create a column, you can first declare a variable of type DataColumn. The
DataColumn class is equipped with five constructors. The default constructor
allows you to create a column without giving details. Here is an example:
using System;
using System.Data;

public class VideoCollection


{
public VideoCollection()
{
DataColumn colCategoryID = new DataColumn();
}
}

If you are planning to reference the column from more than one method, you
should declare it at a class level. Here is an example:

C# 3.0 Practical Learning II 195


using System;
using System.Data;

public class VideoCollection


{
private DataColumn colCategoryID;

public VideoCollection()
{
colCategoryID = new DataColumn();
}
}

To distinguish them, each column must have a specific and unique name. The
name of a column allows you and the compiler to identify a particular
column. The name must follow the rules of variables in C#. To specify the
object name of a column, when creating it, you can use the second
constructor whose syntax is:
public DataColumn(string name);

This constructor expects as argument the name of the column. Here is an


example:
using System;
using System.Data;

public class VideoCollection


{
private DataColumn colCategoryID;

public VideoCollection()
{
colCategoryID = new DataColumn("CategoryID");
}
}

The name of a column is supported with the ColumnName property of the


DataColumn class. This property is of type string.

If you have already declared a DataColumn object, to specify or change its


name, assign the desired string to the DataColumn.ColumnName property.
Here is an example:
using System;
using System.Data;

public class VideoCollection


{
private DataColumn colCategoryID;
private DataColumn colCategory;

public VideoCollection()
{
colCategoryID = new DataColumn("CategoryID");

C# 3.0 Practical Learning II 196


colCategory = new DataColumn();
colCategory.ColumnName = "Category";
}
}

Based on these descriptions, the minimum information needed to create a


column is a name. If you don't specify a name, a default name is assigned to
the new column.

Operations on the Columns of a Table


 

Introduction

The columns of a table are stored in a property called Columns of the


DataTable class. The Columns property is an object of type
DataColumnCollection. The DataColumnCollection class provides
everything that is necessary to create and manage any column. The
DataColumnCollection class is in fact a collection of objects.

Adding a Column to a Table

To make a column part of a table, you must add it to the table's collection of
columns. The DataColumnCollection class is equipped with a method called
Add() that allows you to add a column to the table.

The DataColumnCollection.Add() method is overloaded with 3 versions.


One of the versions uses the following syntax:
public virtual DataColumn Add();

When called, this create creates a new column and return it. The compiler
would assign a default name to the column. If this is the first column, it would
be named Column1. If it is the second column, it would be named Column2,
and so on. You can still specify or change the name of a column created with
the above version of the Add() method. To do this, assign the desired string
to the DataColumn.ColumnName. Here is an example:
using System;
using System.Data;

public class VideoCollection


{
private DataColumn colCategoryID;
private DataColumn colCategory;
private DataColumn colDirectorID;

private DataTable dtDirectors;

public VideoCollection()

C# 3.0 Practical Learning II 197


{
colCategoryID = new DataColumn("CategoryID");
colCategory = new DataColumn();
colCategory.ColumnName = "Category";

dtDirectors = new DataTable();


colDirectorID = dtDirectors.Columns.Add();
}
}

If you want to specify the name of the new column when calling the
DataColumnCollection.Add() method, use the following version:

public virtual DataColumn Add(string name);

This method takes as argument the name of the new column and returns that
new column. Here is an example:
using System;
using System.Data;

public class VideoCollection


{
private DataColumn colCategoryID;
private DataColumn colCategory;

private DataColumn colDirectorID;


private DataColumn colDirector;

private DataTable dtDirectors;

public VideoCollection()
{
colCategoryID = new DataColumn("CategoryID");
colCategory = new DataColumn();
colCategory.ColumnName = "Category";

dtDirectors = new DataTable();


colDirectorID = dtDirectors.Columns.Add();
colDirector = dtDirectors.Columns.Add("Director");
}
}

If you have already formally created a DataColumn object, to add it to the


collection of columns of a table, call the following version of the
DataColumnCollection.Add() method:

public void Add(DataColumn column);

This method expects a DataColumn object as argument. You can either


primarily create a DataColumn value or you can define one in the
parentheses of the method. Here are two examples:
using System;
using System.Data;

C# 3.0 Practical Learning II 198


public class VideoCollection
{
private DataColumn colCategoryID;
private DataColumn colCategory;

private DataColumn colDirectorID;


private DataColumn colDirector;

private DataTable dtDirectors;

private DataTable dtVideos;


private DataColumn colVideo;

public VideoCollection()
{
colCategoryID = new DataColumn("CategoryID");
colCategory = new DataColumn();
colCategory.ColumnName = "Category";

dtDirectors = new DataTable();


colDirectorID = dtDirectors.Columns.Add();
colDirector = dtDirectors.Columns.Add("Director");

dtVideos = new DataTable("Videos");


colVideo = new DataColumn("Video");
dtVideos.Columns.Add(colVideo);
}
}

Practical Learning: Creating Columns

1. To create a few columns, change the file as follows:


 
using System;
using System.Data;

namespace VideoCollection2
{
public class Video
{
private DataSet dsVideoCollection;

private DataColumn colActorName;


private DataColumn colDateOfBirth;
private DataTable tblActors;

private DataTable tblVideos;

public Video()
{
dsVideoCollection = new DataSet("VideoCollection");

tblActors = new DataTable("Actors");

C# 3.0 Practical Learning II 199


colActorName = new DataColumn();
colActorName.ColumnName = "Actor Name";
tblActors.Columns.Add(colActorName);

colDateOfBirth = new DataColumn("Date of Birth");


tblActors.Columns.Add(colDateOfBirth);

dsVideoCollection.Tables.Add(tblActors);

tblVideos = new DataTable("Videos");


dsVideoCollection.Tables.Add(tblVideos);
}

public void ShowTables()


{
int i = 1;

Console.WriteLine("Video Collection - Tables");


foreach (DataTable tbl in dsVideoCollection.Tables)
Console.WriteLine("{0}. {1}", i++,
tbl.TableName);
}
}
}

2. Save the file

Adding an Array of Columns

Instead of adding one column (at a time) to a table, you can first create an
array of columns and add that array to the collection of columns. To do this,
you can call the DataColumnCollection.AddRange() method. Its syntax is:
public void AddRange(DataColumn[] columns);

This method takes as argument an array of predefined columns. Here is an


example:
using System;
using System.Data;

public class VideoCollection


{
private DataTable dtVideos;
private DataColumn[] colVideos;
private DataSet dsVideoCollection;

public VideoCollection()
{
dsVideoCollection = new DataSet("Video");
dtVideos = new DataTable("Video");

colVideos = new DataColumn[7];

C# 3.0 Practical Learning II 200


colVideos[0] = new DataColumn("Title");
colVideos[1] = new DataColumn("Director");
colVideos[2] = new DataColumn("YearReleased");
colVideos[3] = new DataColumn("Length");
colVideos[4] = new DataColumn("Rating");
colVideos[5] = new DataColumn("Format");
colVideos[6] = new DataColumn("Category");

dtVideos.Columns.AddRange(colVideos);

dsVideoCollection.Tables.Add(dtVideos);
}
}

Specifying the Type of Data of a Column

If you create an application that allows the user to enter some values for the
above list of videos, you would wish the user enter the right type of data
under each column. To assist you with, the DataColumn class allows you to
specify an appropriate or desired data type for each column. Just as done in
other regular applications, the data types of a table allow its columns to
accept or reject inappropriate values. Although we saw that the name was
the most important aspect of a column, in reality, a data type is also required.

To supports data types for a column, the DataColumn class relies on the
following .NET Framework structures we have used in previous lessons:
Boolean, Byte , Char, DateTime, Decimal, Double, Int16, Int32, Int64,
SByte, Single, String, TimeSpan, UInt16, UInt32, and UInt64. The
DataColumn class can also support an array of Byte values, as in Byte[], for
a column.

When creating a new column, if you don't specify its data type, it is assumed
to be a string and the string data type is automatically applied to it. To
specify the data type of a column, you have two main alternatives. When
declaring a column, to specify its data type, you can initialize the DataColumn
variable using the third constructor of the class. Its syntax is:
public DataColumn(string columnName, Type dataType);

To specify a column's data type, select one from the Type class of the System
namespace by calling the Type.GetType() method. The GetType() method
is overloaded with three versions. The first version has the following syntax:
public static Type GetType(string typeName);

This method expects as argument a valid data type defined in the .NET
Framework. The data type must be retrieved from the Type class of the
System namespace. The name of the data type must be qualified with a
period operator. Here is an example:

C# 3.0 Practical Learning II 201


using System;
using System.Data;

public class VideoCollection


{
private DataColumn colCategoryID;

public VideoCollection()
{
colCategoryID = new DataColumn("CategoryID",
Type.GetType("System.Int32"));
}
}

If you used the default constructor to declare a DataColumn, to specify its


data type, assign its qualified type to the DataColumn.DataType property.
Here is an example:
using System;
using System.Data;

public class VideoCollection


{
private DataColumn colCategoryID;
private DataColumn colCategory;

public VideoCollection()
{
colCategoryID = new DataColumn("CategoryID",
Type.GetType("System.Int32"));

colCategory = new DataColumn();


colCategory.ColumnName = "Category";
colCategory.DataType = Type.GetType("System.String");
}
}

Remember that there are various techniques you can use to create a column
by specifying its name and its data type.

Practical Learning: Specifying the Data Types of Columns


Columns

1. To create columns with data types and specify the data types of existing
columns, change the Video.cs file as follows:
 
using System;
using System.Data;

namespace VideoCollection2
{
public class Video
{

C# 3.0 Practical Learning II 202


private DataSet dsVideoCollection;

private DataColumn colActorName;


private DataColumn colDateOfBirth;
private DataTable tblActors;

private DataColumn colTitle;


private DataColumn colDirector;
private DataColumn colLength;
private DataColumn colFormat;
private DataColumn colRating;
private DataTable tblVideos;

public Video()
{
dsVideoCollection = new DataSet("VideoCollection");

tblActors = new DataTable("Actors");

colActorName = new DataColumn();


colActorName.ColumnName = "Actor Name";
colActorName.DataType =
Type.GetType("System.String");
tblActors.Columns.Add(colActorName);

colDateOfBirth = new DataColumn("Date of Birth",

Type.GetType("System.DateTime"));
tblActors.Columns.Add(colDateOfBirth);

dsVideoCollection.Tables.Add(tblActors);

tblVideos = new DataTable("Videos");

colTitle = new DataColumn("Title",


Type.GetType("System.String"));
tblVideos.Columns.Add(colTitle);

colDirector = new DataColumn("Director",

Type.GetType("System.String"));
tblVideos.Columns.Add(colDirector);

colLength = new DataColumn("Length",

Type.GetType("System.String"));
tblVideos.Columns.Add(colLength);

colFormat = new DataColumn("Format",

Type.GetType("System.Int16"));
tblVideos.Columns.Add(colFormat);

colRating = new DataColumn("Rating",

Type.GetType("System.Byte"));

C# 3.0 Practical Learning II 203


tblVideos.Columns.Add(colRating);

dsVideoCollection.Tables.Add(tblVideos);
}

public void ShowTables()


{
int i = 1;

Console.WriteLine("Video Collection - Tables");


foreach (DataTable tbl in dsVideoCollection.Tables)
Console.WriteLine("{0}. {1}", i++,
tbl.TableName);
}
}
}

2. Save the file

Columns Maintenance
 

Introduction

Column maintenance consists of adding one or more columns to a table,


identifying an existing column in a table, looking for a column in a table,
deleting one column or deleting all columns of a table. All these operations
are easily supported by the various classes of the System.Data namespace.

The Parent Table of a Column

You are probably now familiar with the relationships among the data set, the
table and the columns. Just in case:

1. A table belongs to a data set and not the contrary. Also, you can create
and use a data set without creating a table

2. A column must belong to a table. A table without at least one column is


no table at all. It is useless

When using the information stored in a table we will learn when studying
records, sometimes you will need to identify the table that owns a particular
column you are accessing. This information can be provided by the Table
property of the DataColumn class.

Identifying a Column

Once again, remember that the group of columns of a table is an object of


type DataColumnCollection. The DataColumnCollection class

C# 3.0 Practical Learning II 204


implements the GetEnumerator() method of the IEnumerable interface.
This allows you to enumerate the columns of a table using foreach.

Practical Learning: Listing the Columns of a table

1. To be able to list the columns of a table, change the videos.cs file as


follows:
 
using System;
using System.Data;

namespace VideoCollection2
{
public class Video
{
private DataSet dsVideoCollection;

private DataColumn colActorName;


private DataColumn colDateOfBirth;
private DataTable tblActors;

private DataColumn colTitle;


private DataColumn colDirector;
private DataColumn colLength;
private DataColumn colFormat;
private DataColumn colRating;
private DataTable tblVideos;

public Video()
{
dsVideoCollection = new DataSet("VideoCollection");

tblActors = new DataTable("Actors");

colActorName = new DataColumn();


colActorName.ColumnName = "Actor Name";
colActorName.DataType =
Type.GetType("System.String");
tblActors.Columns.Add(colActorName);

colDateOfBirth = new DataColumn("Date of Birth",

Type.GetType("System.DateTime"));
tblActors.Columns.Add(colDateOfBirth);

dsVideoCollection.Tables.Add(tblActors);

tblVideos = new DataTable("Videos");

colTitle = new DataColumn("Title",


Type.GetType("System.String"));
tblVideos.Columns.Add(colTitle);

C# 3.0 Practical Learning II 205


colDirector = new DataColumn("Director",
Type.GetType("System.String"));
tblVideos.Columns.Add(colDirector);

colLength = new DataColumn("Length",


Type.GetType("System.String"));
tblVideos.Columns.Add(colLength);

colFormat = new DataColumn("Format",


Type.GetType("System.Int16"));
tblVideos.Columns.Add(colFormat);

colRating = new DataColumn("Rating",


Type.GetType("System.Byte"));
tblVideos.Columns.Add(colRating);

dsVideoCollection.Tables.Add(tblVideos);
}

public void ShowTables()


{
int i = 1;

Console.WriteLine("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=");
Console.WriteLine("Video Collection - Tables");
Console.WriteLine("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=");

foreach (DataTable tbl in dsVideoCollection.Tables)


Console.WriteLine("{0}. {1}", i++,
tbl.TableName);
Console.WriteLine("----------------------------");
}

public void ShowColumns(string table)


{
int i = 1;
DataTable tbl = dsVideoCollection.Tables[table];

Console.WriteLine("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=");
Console.WriteLine("Video Collection - {0} Columns",
table);
Console.WriteLine("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=");

foreach (DataColumn col in tbl.Columns)


Console.WriteLine("{0}. {1}", i++,
col.ColumnName);
Console.WriteLine("----------------------------");
}
}
}

2. give the user the ability to choose, access the Program.cs file and
change it as follows:
 
using System;

C# 3.0 Practical Learning II 206


namespace VideoCollection2
{
public class Program
{
static int Main(string[] args)
{
char answer = 'q';
char choiceTable = '0';
Video vdo = new Video();

do
{
try
{
Console.WriteLine("\nWhat do you want to
do?");
Console.WriteLine("1. Show the tables");
Console.WriteLine("2. Show the columns of a
table");
Console.WriteLine("0. Quit");
Console.Write("Your Choice: ");
answer = char.Parse(Console.ReadLine());

Console.WriteLine("=========================\n");
}
catch (FormatException)
{
Console.WriteLine("Invalid Choice!");
}

switch (answer)
{
case '1':
vdo.ShowTables();
break;
case '2':
Console.WriteLine("Here are the
available tables");
vdo.ShowTables();

try
{
Console.Write("Enter the table whose columns you want to
review: ");
choiceTable =
char.Parse(Console.ReadLine());
}
catch (FormatException)
{
Console.WriteLine("Invalid
answer!");
}
if (choiceTable == '1')
vdo.ShowColumns("Actors");
else if (choiceTable == '2')

C# 3.0 Practical Learning II 207


vdo.ShowColumns("Videos");
break;

default:
break;
}
} while((answer == '1') ||
(answer == '2'));

return 0;
}
}
}

3. Execute the application and test it:


 
What do you want to do?
1. Show the tables
2. Show the columns of a table
0. Quit
Your Choice: 1
=========================

=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Video Collection - Tables
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
1. Actors
2. Videos
----------------------------

What do you want to do?


1. Show the tables
2. Show the columns of a table
0. Quit
Your Choice: 2
=========================

Here are the available tables


=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Video Collection - Tables
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
1. Actors
2. Videos
----------------------------
Enter the table whose columns you want to review: 2
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Video Collection - Videos Columns
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
1. Title
2. Director
3. Length
4. Format
5. Rating
----------------------------

C# 3.0 Practical Learning II 208


What do you want to do?
1. Show the tables
2. Show the columns of a table
0. Quit
Your Choice: 0
=========================

Press any key to continue . . .

4. Close the DOS window

Deleting Columns
 

Deleting a Column by Name

If you happen to have an undesired column in a table, you can delete it. To
perform this operation, the DataColumnCollection class provides the
Remove() method. This method is overloaded in two versions. One of them
uses the following syntax:
public void Remove(string name);

This method expects the name of a column as argument. If the table has that
column, the column would be deleted. Here is an example:
using System;
using System.Data;

namespace VideoCollection
{
public static class Program
{
static DataSet dsVideos;

static DataColumn colTitle;


static DataColumn colDirector;
static DataColumn colLength;
static DataColumn colFormat;
static DataColumn colRating;
static DataTable tblVideos;

static void CreateCollection()


{
dsVideos = new DataSet("Videos");

tblVideos = new DataTable("Video");

colTitle = new DataColumn("Title",


Type.GetType("System.String"));
tblVideos.Columns.Add(colTitle);

C# 3.0 Practical Learning II 209


colDirector = new DataColumn("Director",

Type.GetType("System.String"));
tblVideos.Columns.Add(colDirector);

colLength = new DataColumn("Length",

Type.GetType("System.String"));
tblVideos.Columns.Add(colLength);

colFormat = new DataColumn("Format",

Type.GetType("System.Int16"));
tblVideos.Columns.Add(colFormat);

colRating = new DataColumn("Rating",

Type.GetType("System.Byte"));
tblVideos.Columns.Add(colRating);

dsVideos.Tables.Add(tblVideos);
}

static void ShowTables()


{
int i = 1;

Console.WriteLine("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=");
Console.WriteLine("Video Collection - Tables");
Console.WriteLine("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=");

foreach (DataTable tbl in dsVideos.Tables)


Console.WriteLine("{0}. {1}", i++,
tbl.TableName);
Console.WriteLine("----------------------------");
}

static void ShowColumns(string table)


{
int i = 1;
DataTable tbl = dsVideos.Tables[table];

Console.WriteLine("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=");
Console.WriteLine("Video Collection - {0} Columns",
table);
Console.WriteLine("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=");

foreach (DataColumn col in tbl.Columns)


Console.WriteLine("{0}. {1}", i++,
col.ColumnName);
Console.WriteLine("----------------------------");
}

static int Main(string[] args)


{

C# 3.0 Practical Learning II 210


CreateCollection();

int i = 1;
DataTable tbl = dsVideos.Tables["Video"];

Console.WriteLine("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=");
Console.WriteLine("Video Collection\nColumns of the
Video table");
Console.WriteLine("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=");

foreach (DataColumn col in tbl.Columns)


Console.WriteLine("{0}. {1}", i++,
col.ColumnName);
Console.WriteLine("----------------------------");

tbl.Columns.Remove("Length");

Console.WriteLine("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=");
Console.WriteLine("Video Collection\nColumns of the
Video table");
Console.WriteLine("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=");

i = 1;
foreach (DataColumn col in tbl.Columns)
Console.WriteLine("{0}. {1}", i++,
col.ColumnName);
Console.WriteLine("----------------------------");

return 0;
}
}
}

This would produce:


=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Video Collection
Columns of the Video table
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
1. Title
2. Director
3. Length
4. Format
5. Rating
----------------------------
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Video Collection
Columns of the Video table
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
1. Title
2. Director
3. Format
4. Rating
----------------------------
Press any key to continue . . .

C# 3.0 Practical Learning II 211


If there is no column with the name passed as argument to the
DataColumnCollection.Remove() method, the compiler would throw an
ArgumentException exception. As this can only be undesirable, the
DataColumnCollection class allows you to check the existence of the
column on the table. This is done by calling the Contains() method whose
syntax is:
public bool Contains(string name);

Here is an example of calling it:


using System;
using System.Data;

namespace VideoCollection
{
public static class Program
{
. . . No Change

static int Main(string[] args)


{
CreateCollection();

int i = 1;
DataTable tbl = dsVideos.Tables["Video"];

Console.WriteLine("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=");
Console.WriteLine("Video Collection\nColumns of the
Video table");
Console.WriteLine("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=");

foreach (DataColumn col in tbl.Columns)


Console.WriteLine("{0}. {1}", i++,
col.ColumnName);
Console.WriteLine("----------------------------");

if (tbl.Columns.Contains("Length"))
{
tbl.Columns.Remove("Length");

Console.WriteLine("=-=-=-=-=-=-=-=-=-=-=-=-=-=-
=");
Console.WriteLine("Video Collection\nColumns of
the Video table");
Console.WriteLine("=-=-=-=-=-=-=-=-=-=-=-=-=-=-
=");

i = 1;
foreach (DataColumn col in tbl.Columns)
Console.WriteLine("{0}. {1}", i++,
col.ColumnName);

Console.WriteLine("----------------------------");
}

C# 3.0 Practical Learning II 212


return 0;
}
}
}

Even if the table contains that column, it may not allow the column to be be
deleted. For this reason, you should first check that the table allows that the
column be deleted. To assist you with checking this, the
DataColumnCollection class is equipped with the CanRemove() method. Its
syntax is:
public bool CanRemove(DataColumn column);

Deleting a Column by Index

The columns of a table are arranged in an indexed list with the first (the most
left) column at index 0, the second (from left) at index 1, and so on. To
delete a column based on its index, you can call the
DataColumnCollection.RemoveAt() method. Its syntax is:

public void RemoveAt(int index);

The index of the column is passed to this method. When calling this method,
make sure you pass a valid index that is an integer greater than or equal to 0
but less than the DataColumnCollection.Count - 1. Here is an example:
using System;
using System.Data;

namespace VideoCollection
{
public static class Program
{
. . . No Change

static int Main(string[] args)


{
CreateCollection();

int i = 1;
DataTable tbl = dsVideos.Tables["Video"];

Console.WriteLine("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=");
Console.WriteLine("Video Collection\nColumns of the
Video table");
Console.WriteLine("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=");

foreach (DataColumn col in tbl.Columns)


Console.WriteLine("{0}. {1}", i++,
col.ColumnName);
Console.WriteLine("----------------------------");

tbl.Columns.RemoveAt(4);

C# 3.0 Practical Learning II 213


Console.WriteLine("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=");
Console.WriteLine("Video Collection\nColumns of the
Video table");
Console.WriteLine("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=");

i = 1;
foreach (DataColumn col in tbl.Columns)
Console.WriteLine("{0}. {1}", i++,
col.ColumnName);
Console.WriteLine("----------------------------");

return 0;
}
}
}

If you pass a negative index of a number >=


DataColumnCollection.Count, the compiler would throw an
IndexOutOfRangeException exception. If you know the object name of the
column, you can first get its index by calling the
DataColumnCollection.IndexOf() method and then pass its returned
value to the RemoveAt() method.

Clearing the Table of Columns

To delete all columns from a table, you can call the


DataColumnCollection.Clear() method. Its syntax is:

public void Clear();

After this method has been called, all columns from the table are deleted.

C# 3.0 Practical Learning II 214


The Records of a Table
 

The Rows of a Table


 

Introduction to Records

In our description of tables, we saw that a table was made of one or various
columns that represented some categories of data. Here is an example of a
table with a few columns:
using System;
using System.Data;

namespace VideoCollection

    public static  class Program


    {
        static DataSet dsVideos;

        static DataColumn colShelfNumber;


        static DataColumn colTitle;
        static DataColumn colDirector;
        static DataColumn colLength;
        static DataColumn colYear;
        static DataColumn colRating;
        static DataTable tblVideos;

        static void CreateCollection()


        {
            dsVideos = new DataSet("Videos");

            tblVideos = new DataTable("Video");

            colShelfNumber = new DataColumn("ShelfNumber",


                                    
Type.GetType("System.String"));
            tblVideos.Columns.Add(colShelfNumber);

            colTitle = new DataColumn("Title",


                Type.GetType("System.String"));
            tblVideos.Columns.Add(colTitle);

            colDirector = new DataColumn("Director",

C# 3.0 Practical Learning II 215


                                        
Type.GetType("System.String"));
            tblVideos.Columns.Add(colDirector);

            colLength = new DataColumn("Length",


                                      
Type.GetType("System.String"));
            tblVideos.Columns.Add(colLength);

            colYear = new DataColumn("Year",


                                      
Type.GetType("System.Int16"));
            tblVideos.Columns.Add(colYear);

            colRating = new DataColumn("Rating",


                                      
Type.GetType("System.String"));
            tblVideos.Columns.Add(colRating);

            dsVideos.Tables.Add(tblVideos);
        }

        static int Main(string[] args)


        {
            CreateCollection();

            return 0;
        }
    }
}

After creating such a table and its columns, you (actually the user) can enter
values in the table to make it a valuable list. Filling up a table with values is
referred to as data entry.

Practical Learning: Introducing Data Records

1. Start Microsoft Visual C# and create a Console Application named


CollegeParkAutoParts4

2. To save the application, on the Standard toolbar, click the Save All
button

3. Accept all defaults and click Save

The Row of a Table

A record on a table is represented as a row (horizontal) of data. A row, or


record, is an object based on the DataRow class.

To support the various records that belong to a table, the DataTable class is
equipped with a property called Rows. The DataTable.Rows property is an

C# 3.0 Practical Learning II 216


object of the DataRowCollection class. The DataRowCollection class
provides the necessary properties and methods you can use to create and
manage records of a table. 

Introduction to Data Entry

When performing data entry and while doing it on a record, the record has a
status that can be identified by the DataRow.RowState property which is a
value based on the DataRowState enumerator.

A record on a table is represented as a row of data. To support the various


records that belong to a table, the DataTable class is equipped with the Rows
property which is an object of type DataRowCollection with each record
being an object of type DataRow.

Before adding a new record to a table, you must let the table know. This is
done by calling the DataTable.NewRow() method. Its syntax is:
public DataRow NewRow();

The DataTable.NewRow() method returns a DataRow object. Here is an


example of calling it:
using System;
using System.Data;

namespace VideoCollection
{
public static class Program
{
. . . No Change

static void CreateRecord()


{
DataRow rowVideo = tblVideos.NewRow();
}

static int Main(string[] args)


{
return 0;
}
}
}

Data Entry
 

Introduction

When you call the DataTable.NewRow() method, the record's status is


DataRowState.Detached. After calling the DataTable.NewRow() method,

C# 3.0 Practical Learning II 217


you can specify the value that the column would carry. To do this, you must
specify the table's column whose value you want to provide. You can locate a
column based on an index as we mentioned already that the columns of a
table are stored in the DataTable.Columns property which is based on the
DataColumnCollection class. An example would be rowVideo["Title"], which
specifies the column named Title. After specifying the column, assign it the
desired but appropriate value based on the DataColumn.DataType value you
would have provided. Here are examples of assigning values to the columns
of a table:
using System;
using System.Data;

namespace VideoCollection
{
public static class Program
{
. . . No Change

static void CreateRecord()


{
DataRow rowVideo = tblVideos.NewRow();

rowVideo[0] = "GT-682";
rowVideo[1] = "A Few Good Men";
rowVideo[2] = "Rob Reiner";
rowVideo[3] = "138 Minutes";
rowVideo[4] = 1992;
rowVideo[5] = "R";
}

static int Main(string[] args)


{
return 0;
}
}
}

Each column can also be identified by its index in the table. 

Adding a Record to a Table

After specifying the value(s) of the column(s), you must add it (them) to the
table. To do this, you must call the Add() method of the
DataRowCollection class. This method is overloaded with two versions. One
of the versions uses the following syntax:
public void Add(DataRow row);

This method expects the name of the record as argument, which would be
the value returned by a previous call to the DataTable.NewRow() method.
Here is an example:

C# 3.0 Practical Learning II 218


using System;
using System.Data;

namespace VideoCollection
{
public static class Program
{
. . . No Change

static void CreateRecord()


{
DataRow rowVideo = tblVideos.NewRow();

rowVideo[0] = "GT-682";
rowVideo[1] = "A Few Good Men";
rowVideo[2] = "Rob Reiner";
rowVideo[3] = "138 Minutes";
rowVideo[4] = 1992;
rowVideo[5] = "R";

tblVideos.Rows.Add(rowVideo);
}

static int Main(string[] args)


{
return 0;
}
}
}

When the record has been added to the table, the record has a status of
DataRowState.Added.

Adding an Array of Records

The above version of the DataRowCollection.Add() method means that


you must identify each column before assigning a value to it. If you already
know the sequence of columns and don't need to explicitly identify them, you
can store all values in an array and simply add the array as a complete
record. To support this, the DataRowCollection class provide another
version of the .Add() method whose syntax is:
public virtual DataRow Add(object[] values);

Here is an example:
using System;
using System.Data;

namespace VideoCollection
{
public static class Program
{
. . . No Change

C# 3.0 Practical Learning II 219


static void CreateRecord()
{
object[] arrRecord = { "MM-258",
"Fatal Attraction",
"Adrian Lyne", 1987,
"120 Minutes", "R" };

tblVideos.Rows.Add(arrRecord);
}

static int Main(string[] args)


{
return 0;
}
}
}

There is an alternative to this second version of the


DataRowCollection.Add() method. As opposed to passing an array of
values to the Add() method, you can first define an array, assign that array
to a DataRow variable, then pass that DataRow object to the Add() method.
To support this technique, the DataRow class is equipped with an ItemArray
property that expects an array. Here is an example
using System;
using System.Data;

namespace VideoCollection
{
public static class Program
{
. . . No Change

static void CreateRecord()


{
object[] arrVideo = { "FD-205", "Her Alibi", "Bruce
Beresford",
"94 Minute", 1989, "PG-
13" };

DataRow rowVideo = tblVideos.NewRow();


rowVideo.ItemArray = arrVideo;

tblVideos.Rows.Add(rowVideo);
}

static int Main(string[] args)


{
return 0;
}
}
}

C# 3.0 Practical Learning II 220


After creating the records of a table, if a record contains invalid values, the
DataRow.HasErrors property can help you identify them.

The Number of Records of a Table

After you have created a table and its columns but before adding any row,
the number of the table's record is set to 0. Every time you add a new record,
the number of records is incremented by 1. To get the number of records that
a table contains, access the Count property of its DataRowCollection. The
Count property is inherited from the InternalDataCollectionBase class,
which is the parent of many collection classes.

Saving the Records of a Table


 

Introduction

When the application closes, unfortunately, all the information created while
the application was running is lost. While the first goal of an application is to
create one or more lists used to organize information, probably the essence of
an information-based or a data-based application is to preserve information
created when using the application and be able to retrieve that information
the next time the application runs, without re-creating it.

Of course, there are various ways you can save the information created in an
application. As the DataSet class is equipped with all the necessary features
used to create and manage one or more lists of an application, it also
provides a very high level of saving the information stored in its lists.

Saving a Data Set

Once a new record has been created or when the lists of the data set have
been populated with information, you can save the changes and store them
to a computer file. By default, the DataSet class is equipped to save its lists
as XML. To support this, it is equipped with the WriteXml() method that is
overloaded with various versions. One of the versions of this method uses the
following syntax:
public void WriteXml(string fileName);

This method takes as argument the name of the new file or its path. When
providing this argument, make sure you add the .xml extension to the file
name. This method does two things: it checks the existence of the file and it
saves it. If the file you provided is not found in the path, this method creates
it and writes the record(s) to it. If the file exists already, this method opens it,
finds its end, and appends the new data at the end. This makes the method
very useful and friendly.

C# 3.0 Practical Learning II 221


Here is an example of saving a data set using this method:
using System;
using System.IO;
using System.Data;

namespace VideoCollection
{
public static class Program
{
static DataSet dsVideos;

static DataColumn colShelfNumber;


static DataColumn colTitle;
static DataColumn colDirector;
static DataColumn colLength;
static DataColumn colYear;
static DataColumn colRating;
static DataTable tblVideos;

static string strDirectory;

static void CreateCollection()


{
dsVideos = new DataSet("Videos");

tblVideos = new DataTable("Video");

colShelfNumber = new DataColumn("ShelfNumber",


Type.GetType("System.String"));
tblVideos.Columns.Add(colShelfNumber);

colTitle = new DataColumn("Title",


Type.GetType("System.String"));
tblVideos.Columns.Add(colTitle);

colDirector = new DataColumn("Director",

Type.GetType("System.String"));
tblVideos.Columns.Add(colDirector);

colLength = new DataColumn("Length",

Type.GetType("System.String"));
tblVideos.Columns.Add(colLength);

colYear = new DataColumn("Year",

Type.GetType("System.Int16"));
tblVideos.Columns.Add(colYear);

colRating = new DataColumn("Rating",

Type.GetType("System.String"));
tblVideos.Columns.Add(colRating);

C# 3.0 Practical Learning II 222


dsVideos.Tables.Add(tblVideos);

strDirectory = @"C:\Video Collection";


Directory.CreateDirectory(strDirectory);
dsVideos.WriteXml(strDirectory + @"\videos.xml");
}

static void CreateRecord()


{
DataRow rowVideo = tblVideos.NewRow();

rowVideo[0] = "GT-682";
rowVideo[1] = "A Few Good Men";
rowVideo[2] = "Rob Reiner";
rowVideo[3] = "138 Minutes";
rowVideo[4] = 1992;
rowVideo[5] = "R";

tblVideos.Rows.Add(rowVideo);
dsVideos.WriteXml(strDirectory + @"\videos.xml");
}

static int Main(string[] args)


{
CreateCollection();
CreateRecord();

return 0;
}
}
}

If you want to control whether the file should be created from scratch,
instead of passing the name of the file to this method, first create a stream
using a Stream-derived class such as FileStream. This allows specifying the
necessary options using the FileMode, FileAccess, and FileShare
properties. Once the stream is ready, pass it to the WriteXml() method
because it is also overloaded with the following syntax:
public void WriteXml(Stream stream);

Here is an example:
using System;
using System.IO;
using System.Data;

namespace VideoCollection
{
public static class Program
{
. . . No Change

static void CreateRecord()


{

C# 3.0 Practical Learning II 223


FileStream fsVideos = new FileStream(strDirectory +
@"\videos.xml",

FileMode.Create,

FileAccess.Write);
object[] rowVideo = { "MM-258", "Fatal Attraction",
"Adrian Lyne",
"120 Minutes", 1987, "R" };

tblVideos.Rows.Add(rowVideo);
dsVideos.WriteXml(fsVideos);

fsVideos.Close();
}

static int Main(string[] args)


{
CreateCollection();
CreateRecord();

return 0;
}
}
}

If you want the file to be formatted as text, you can use the following version
of the method:
public void WriteXml(TextWriter writer);

If you prefer to use an XmlWriter variable to manage the file, use the
following version of the method:
public void WriteXml(XmlWriter writer);

Obviously to use this method, you must first define an XmlWriter type of
variable.

Practical Learning: Creating a Data Set

1. To create a new class, on the main menu, click Project -> Add Class...

2. Set the Name to Inventory and click Add

3. Change the file as follows:


 
using System;
using System.IO;
using System.Xml;
using System.Data;

namespace CollegeParkAutoParts4

C# 3.0 Practical Learning II 224


{
public class Inventory
{
private DataColumn colPartNumber;
private DataColumn colYear;
private DataColumn colMake;
private DataColumn colModel;
private DataColumn colPartName;
private DataColumn colPartPrice;

private DataColumn colItemNumber;


private DataColumn colItemName;
private DataColumn colItemPrice;

private DataTable tblAutoParts;


private DataTable tblStoreItems;
private DataSet dsStoreItems;

string strDirectory;
string strFilename;

public Inventory()
{
colPartNumber = new DataColumn("PartNumber",
Type.GetType("System.Int32"));
colYear = new DataColumn("Year",
Type.GetType("System.Int32"));
colMake = new DataColumn("Make",
Type.GetType("System.String"));
colModel = new DataColumn("Model",
Type.GetType("System.String"));
colPartName = new DataColumn("PartName",
Type.GetType("System.String"));
colPartPrice = new DataColumn("PartPrice",
Type.GetType("System.Double"));

tblAutoParts = new DataTable("AutoPart");


tblAutoParts.Columns.Add(colPartNumber);
tblAutoParts.Columns.Add(colYear);
tblAutoParts.Columns.Add(colMake);
tblAutoParts.Columns.Add(colModel);
tblAutoParts.Columns.Add(colPartName);
tblAutoParts.Columns.Add(colPartPrice);

tblStoreItems = new DataTable("StoreItem");


colItemNumber = new DataColumn("ItemNumber",
Type.GetType("System.Int32"));
colItemName = new DataColumn("ItemName",
Type.GetType("System.String"));
colItemPrice = new DataColumn("ItemPrice",
Type.GetType("System.Double"));
tblStoreItems .Columns.Add(colItemNumber);
tblStoreItems.Columns.Add(colItemName);
tblStoreItems.Columns.Add(colItemPrice);

dsStoreItems = new DataSet("StoreItems");

C# 3.0 Practical Learning II 225


dsStoreItems.Tables.Add(tblAutoParts);
dsStoreItems.Tables.Add(tblStoreItems);

strDirectory = @"C:\College Park Auto Parts";


strFilename = strDirectory + "\\" +
"StoreItems.xml";
DirectoryInfo dirInfo = new
DirectoryInfo(strDirectory);

if (!dirInfo.Exists)
dirInfo.Create();
}

public void CreateStoreItem()


{
int year = 1960;
int iPartNumber = 0, iItemNumber = 0;
double unitPrice = 0.00D;
string strMake = "Unknown", strModel = "Unknown",
strPartName = "N/A", strItemName = "N/A";
int typeOfItem = 0;
char ansAdd = 'n';

if (File.Exists(strFilename))
dsStoreItems.ReadXml(strFilename);

do
{
try
{
Console.WriteLine("What type of item do you
want to add");
Console.WriteLine("1. An auto part (for a car or
an engine)");
Console.WriteLine("2. Another type of item,
" +
"not for a specific car");
Console.WriteLine("0. Stop");
Console.WriteLine("Enter the following pieces of
information");
Console.Write("Your Choice: ");
typeOfItem = int.Parse(Console.ReadLine());

if (typeOfItem == 1)
{
Random rndPartNumber = new Random();
iPartNumber = rndPartNumber.Next(100000,
999999);

try
{
Console.Write("Car Year:
");
year =
int.Parse(Console.ReadLine());
}

C# 3.0 Practical Learning II 226


catch (FormatException)
{
Console.WriteLine("Invalid year");
}
Console.Write("Make (or None if N/A):
");
strMake = Console.ReadLine();
Console.Write("Model (or None if N/A):
");
strModel = Console.ReadLine();
Console.Write("Part Name:
");
strPartName = Console.ReadLine();

try
{
Console.Write("Unit Price:
");
unitPrice =
double.Parse(Console.ReadLine());
}
catch (FormatException)
{
Console.WriteLine("Invalid unit
price");
}

Console.WriteLine("\nHere is a summary
of " +
"the part to be added");

Console.WriteLine("--------------------------------");
Console.WriteLine("Part Number: {0}",
iPartNumber);
Console.WriteLine("Year: {0}",
year);
Console.WriteLine("Make: {0}",
strMake);
Console.WriteLine("Model: {0}",
strModel);
Console.WriteLine("Part Name: {0}",
strPartName);
Console.WriteLine("Unit Price: {0:C}",
unitPrice);

Console.WriteLine("--------------------------------");

Console.Write("Are you ready to add it "


+
"to the database (y/n)? ");
ansAdd = char.Parse(Console.ReadLine());
if ((ansAdd == 'y') || (ansAdd == 'Y'))
{
DataRow part =
tblAutoParts.NewRow();
part["PartNumber"] = iPartNumber;

C# 3.0 Practical Learning II 227


part["Year"] = year;
part["Make"] = strMake;
part["Model"] = strModel;
part["PartName"] = strPartName;
part["PartPrice"] = unitPrice;
tblAutoParts.Rows.Add(part);

dsStoreItems.WriteXml(strFilename);
}
else
Console.WriteLine("The part will not
be " +
"added to the
database");
}
else if (typeOfItem == 2)
{
Random rndPartNumber = new Random();
iItemNumber = rndPartNumber.Next(100000,
999999);

Console.Write("Item/Description: ");
strItemName = Console.ReadLine();

try
{
Console.Write("Unit Price: ");
unitPrice =
double.Parse(Console.ReadLine());
}
catch (FormatException)
{
Console.WriteLine("Invalid unit price");
}

Console.WriteLine("\nHere is a summary of" +


" the part to be added");

Console.WriteLine("--------------------------------");
Console.WriteLine("Item Number: {0}",
iItemNumber);
Console.WriteLine("Name/Descr: {0}",
strItemName);
Console.WriteLine("Unit Price: {0:C}",
unitPrice);

Console.WriteLine("--------------------------------");

Console.Write("Are you ready to add it " +


"to the database (y/n)? ");
ansAdd = char.Parse(Console.ReadLine());
if ((ansAdd == 'y') || (ansAdd == 'Y'))
{
DataRow item = tblStoreItems.NewRow();
item["ItemNumber"] = iItemNumber;
item["ItemName"] = strItemName;

C# 3.0 Practical Learning II 228


item["ItemPrice"] = unitPrice;
tblStoreItems.Rows.Add(item);

dsStoreItems.WriteXml(strFilename);
}
else
Console.WriteLine("The part will not be
" +
"added to the database");
}
}
catch (FormatException)
{
Console.WriteLine("Invalid Menu Selection");
}
} while (typeOfItem == 1 || typeOfItem == 2);
}

public void ShowInventory()


{
}
}
}

4. Access the Program.cs file and change it as follows:


 
using System;

namespace CollegeParkAutoParts4
{
class Program
{
static int Main(string[] args)
{
Inventory item = new Inventory();

item.CreateStoreItem();

Console.WriteLine();
return 0;
}
}
}

5. Execute the application and create the following items:


 
What type of item do you want to add
1. An auto part (for a car or an engine)
2. Another type of item, not for a specific car
0. Stop
Enter the following pieces of information
Your Choice: 1
Car Year: 2005
Make (or None if N/A): Acura

C# 3.0 Practical Learning II 229


Model (or None if N/A): NSX 3.0L V6
Part Name: Oil Filter
Unit Price: 8.85

Here is a summary of the part to be added


--------------------------------
Part Number: 421960
Year: 2005
Make: Acura
Model: NSX 3.0L V6
Part Name: Oil Filter
Unit Price: $8.85
--------------------------------
Are you ready to add it to the database (y/n)? y
What type of item do you want to add
1. An auto part (for a car or an engine)
2. Another type of item, not for a specific car
0. Stop
Enter the following pieces of information
Your Choice: 1
Car Year: 2002
Make (or None if N/A): Audi
Model (or None if N/A): Quattro 1.8L Turbo
Part Name: Clutch Release Bearing
Unit Price: 55.50

Here is a summary of the part to be added


--------------------------------
Part Number: 234374
Year: 2002
Make: Audi
Model: Quattro 1.8L Turbo
Part Name: Clash Bear
Unit Price: $55.50
--------------------------------
Are you ready to add it to the database (y/n)? y
What type of item do you want to add
1. An auto part (for a car or an engine)
2. Another type of item, not for a specific car
0. Stop
Enter the following pieces of information
Your Choice: 1
Car Year: BMW
Invalid year
Make (or None if N/A): BMW
Model (or None if N/A): 325I 2.5L L6
Part Name: Ignition Coil
Unit Price: 60.85

Here is a summary of the part to be added


--------------------------------
Part Number: 899611
Year: 2002
Make: BMW
Model: 325i 2.5L L6
Part Name: Ignition Coil

C# 3.0 Practical Learning II 230


Unit Price: $60.85
--------------------------------
Are you ready to add it to the database (y/n)? n
The part will not be added to the database
What type of item do you want to add
1. An auto part (for a car or an enfine)
2. Another type of item, not for a specific car
0. Stop
Enter the following pieces of information
Your Choice: 1
Car Year: 2002
Make (or None if N/A): BMW
Model (or None if N/A): 325i 2.5L L6
Part Name: Ignition Coil
Unit Price: 60.85

Here is a summary of the part to be added


--------------------------------
Part Number: 761840
Year: 2002
Make: BMW
Model: 325I 2.5L L6
Part Name: Ignition Coil
Unit Price: $60.85
--------------------------------
Are you ready to add it to the database (y/n)? Y
What type of item do you want to add
1. An auto part (for a car or an engine)
2. Another type of item, not for a specific car
0. Stop
Enter the following pieces of information
Your Choice: 2
Item/Description: Soda 2L Bottle
Unit Price: 1.75

Here is a summary of the part to be added


--------------------------------
Item Number: 894761
Name/Descr: Soda 2L Bottle
Unit Price: $1.75
--------------------------------
Are you ready to add it to the database (y/n)? Y
What type of item do you want to add
1. An auto part (for a car or an engine)
2. Another type of item, not for a specific car
0. Stop
Enter the following pieces of information
Your Choice: 2
Item/Description: 2
Unit Price: 3

Here is a summary of the part to be added


--------------------------------
Item Number: 722464
Name/Descr: 2
Unit Price: $3.00

C# 3.0 Practical Learning II 231


--------------------------------
Are you ready to add it to the database (y/n)? n
The part will not be added to the database
What type of item do you want to add
1. An auto part (for a car or an engine)
2. Another type of item, not for a specific car
0. Stop
Enter the following pieces of information
Your Choice: 2
Item/Description: STP Gas Treatment 3-Pack
Unit Price: 2.99

Here is a summary of the part to be added


--------------------------------
Item Number: 126066
Name/Descr: STP Gas Treatment 3-Pack
Unit Price: $2.99
--------------------------------
Are you ready to add it to the database (y/n)? Y
What type of item do you want to add
1. An auto part (for a car or an enfine)
2. Another type of item, not for a specific car
0. Stop
Enter the following pieces of information
Your Choice: 0

Press any key to continue . . .

6. Close the DOS window

7. Open the file in a browser to see the result

Opening a Data Set

To open the data saved from a list, the DataSet class provides the
ReadXml() method that is overloaded with various versions. One of the
versions of this method uses the following syntax:
public XmlReadMode ReadXml(string fileName);

This method takes as argument the name of an existing XML file or its path.
The method opens the file and provides the XML formatting as it was done
when the file was saved. Here is an example of calling this method:
using System;
using System.IO;
using System.Data;

namespace VideoCollection
{
public static class Program
{
static DataSet dsVideos;

C# 3.0 Practical Learning II 232


static DataColumn colShelfNumber;
static DataColumn colTitle;
static DataColumn colDirector;
static DataColumn colLength;
static DataColumn colYear;
static DataColumn colRating;
static DataTable tblVideos;

static string strDirectory;

static void CreateCollection()


{
dsVideos = new DataSet("Videos");

tblVideos = new DataTable("Video");

colShelfNumber = new DataColumn("ShelfNumber",


Type.GetType("System.String"));
tblVideos.Columns.Add(colShelfNumber);

colTitle = new DataColumn("Title",


Type.GetType("System.String"));
tblVideos.Columns.Add(colTitle);

colDirector = new DataColumn("Director",

Type.GetType("System.String"));
tblVideos.Columns.Add(colDirector);

colLength = new DataColumn("Length",

Type.GetType("System.String"));
tblVideos.Columns.Add(colLength);

colYear = new DataColumn("Year",

Type.GetType("System.Int16"));
tblVideos.Columns.Add(colYear);

colRating = new DataColumn("Rating",

Type.GetType("System.String"));
tblVideos.Columns.Add(colRating);

dsVideos.Tables.Add(tblVideos);

strDirectory = @"C:\Video Collection";


Directory.CreateDirectory(strDirectory);
}

static void CreateRecord()


{
if (File.Exists(strDirectory + @"\videos.xml"))
dsVideos.ReadXml(strDirectory + @"\videos.xml");

C# 3.0 Practical Learning II 233


object[] arrVideo = { "FD-205", "Her Alibi", "Bruce
Beresford",
"94 Minute", 1989, "PG-
13" };

DataRow rowVideo = tblVideos.NewRow();


rowVideo.ItemArray = arrVideo;

tblVideos.Rows.Add(rowVideo);
dsVideos.WriteXml(strDirectory + @"\videos.xml");
}

static int Main(string[] args)


{
CreateCollection();
CreateRecord();

return 0;
}
}
}

Although this method can read any XML file, if you use it to open a file that
was saved by someone else or another application and you want to use it in
your application, you should be familiar with the names of its nodes. If it
contains names that are not "registered" or recognized by your DataSet
object, the lists that compose your application may not be able to read it, not
because the list was not formatted right, but because the lists of your
application would be holding different names.

If the file was saved using a Stream-based class, you can pass a stream to
the method based on the following syntax:
public XmlReadMode ReadXml(Stream stream);

In the same way, the method provides an equivalent version for the
TextWriter and the XmlWriter versions:

public XmlReadMode ReadXml(TextReader reader);


public XmlReadMode ReadXml(XmlReader reader);

To use one of these versions, you must first define a TextWriter or an


XmlReader type of variable.

When retrieving the content of the XML file, if you want it delivered as text,
call the DataSet.GetXml() method. Its syntax is:
public string GetXml();

As you can see, this method returns a String string.

Once a file has been opened, you can explore its content. The most obvious
operation related to opening a data set consists of viewing its records.

C# 3.0 Practical Learning II 234


Committing or Rejecting Changes to a List

When a user has created a record, the data set that holds the information is
considered to have been modified because, obviously, it doesn't have the
same information or the same records it had when the application was
launched. You, as the programmer, have the option of accepting the changes
or rejecting them. To accept the changes, call the
DataSet.AcceptChanges() method. Its syntax is:

public void AcceptChanges();

If you don't want the changes to take effect, you can reject them by calling
the DataSet.RejectChanges() method. Its syntax is:
public virtual void RejectChanges();

This method can be called to dismiss whatever changes where made on the
records of the list(s).

Locating Records and Their Values


 

Locating a Record

Before performing any operation on a record, you must be able to locate it.
That is, you must be able to identify a record among the various records of a
table. To locate a record in the DataTable.Rows collection, the
DataRowCollection class has an indexed property that is defined as follows:

public DataRow this[int index] {get;}

The records of a table are stored in a list (called the DataRowCollection).


The first record has an index of 0. The second record has an index of 1, and
so on. Here is an example of using it to retrieve the information stored in a
record:
DataRow row = this.dtVideos.Rows[2];

When you pass an index to this property, the compiler would check whether
the record exists. If a record with that index exists, its DataRow value is
produced.

In the previous lessons, we learned how to locate a column using the


foreach loop to visit the members of a DataColumnCollection collection.
Like the DataColumnCollection class, the DataRowCollection class
implements the GetEnumerator() method of the IEnumerable interface.
This means that you can apply the foreach loop to its collection of records to
visit each collection. As mentioned already, to access a record, you can pass

C# 3.0 Practical Learning II 235


its index to the indexed property of the DataRowCollection, which produces
a DataRow object. Using these concepts, you can access the values of a table.
Here is an example:
using System;
using System.IO;
using System.Data;

namespace VideoCollection
{
public static class Program
{
. . . No Change

static void ShowVideos()


{
dsVideos.ReadXml(strDirectory + @"\videos.xml");

Console.WriteLine("Video Collection");

Console.WriteLine("================================");
foreach (DataRow row in tblVideos.Rows)
{
foreach (DataColumn col in tblVideos.Columns)
{
Console.WriteLine("{0}", row[col]);
}

Console.WriteLine("--------------------------------");
}
}

static int Main(string[] args)


{
CreateCollection();
ShowVideos();

return 0;
}
}
}

This would produce:


Video Collection
================================
GT-682
A Few Good Men
Rob Reiner
138 Minutes
1992
R
--------------------------------
MM-258
Fatal Attraction
Adrian Lyne

C# 3.0 Practical Learning II 236


120 Minutes
1987
R
--------------------------------
FD-205
Her Alibi
Bruce Beresford
94 Minute
1989
PG-13
--------------------------------
Press any key to continue . . .

The DataRow class itself is equipped with an indexed property that allows you
to access the value stored in a particular column. For example, you can use a
for loop to visit each column by its index. Once you get to a column, you can
then use the indexed property of a row to access the value stored under that
column. Here are examples:
using System;
using System.IO;
using System.Data;

namespace VideoCollection
{
public static class Program
{
. . . No Change

static void ShowVideos()


{
dsVideos.ReadXml(strDirectory + @"\videos.xml");

Console.WriteLine("================================");
Console.WriteLine("Video Collection");

Console.WriteLine("================================");
for (int i = 0; i < tblVideos.Rows.Count; i++)
{
DataRow row = tblVideos.Rows[i];
Console.WriteLine("Shelf #: {0}",
tblVideos.Rows[i]["ShelfNumber"]);
Console.WriteLine("Title: {0}",
tblVideos.Rows[i]["Title"]);
Console.WriteLine("Director: {0}",
tblVideos.Rows[i]["Director"]);
Console.WriteLine("Length: {0}",
tblVideos.Rows[i]["Length"]);
Console.WriteLine("Year: {0}",
tblVideos.Rows[i]["Year"]);
Console.WriteLine("Rating: {0}",
tblVideos.Rows[i]["Rating"]);

Console.WriteLine("--------------------------------");

C# 3.0 Practical Learning II 237


}
}

static int Main(string[] args)


{
CreateCollection();
ShowVideos();

return 0;
}
}
}

This would produce:


================================
Video Collection
================================
Shelf #: GT-682
Title: A Few Good Men
Director: Rob Reiner
Length: 138 Minutes
Year: 1992
Rating: R
--------------------------------
Shelf #: MM-258
Title: Fatal Attraction
Director: Adrian Lyne
Length: 120 Minutes
Year: 1987
Rating: R
--------------------------------
Shelf #: FD-205
Title: Her Alibi
Director: Bruce Beresford
Length: 94 Minute
Year: 1989
Rating: PG-13
--------------------------------
Press any key to continue . . .

When using any of these previous techniques (whether using for or


foreach), if you specify an index that is either less than 0 or beyond the
number of records in the table, the compiler would throw an
IndexOutOfRangeException exception.

Locating a Value

As mentioned already, a record is in fact one or a group of values from each


of the columns of the table. Consider the following table:

Title Director Length © Year Rating

C# 3.0 Practical Learning II 238


A Few Good Men Rob Reiner 138 Minutes 1992 R

The Distinguished
Jonathan Lynn 112 Minutes   R
Gentleman

Joel Coen & Ethan


The Lady Killers 104 Minutes   R
Coen

Fatal Attraction Adrian Lyne 120 Minutes 1987 R

Her Alibi Bruce Beresford 94 Minutes 1989 PG-13

The Manchurian Candidate Jonathan Demme 129 Minutes 2004 R

The "A Few Good Men" string is a value of the Title column. In the same way,
1992 is a value of the Year column. In some circumstances, you will need to
locate a particular value in order to perform an operation on it. You can start
by locating the record you need and return its DataRow object. To know the
table that the record belongs to, access its DataRow.Table property. This
property is declared as follows:
public DataTable Table {get;}

To locate the value that a record holds under a particular column, the
DataRow class had an indexed property that is overloaded with various
versions (actually six, but at this time we are interested in the first three
only). One of the versions of this property uses the following syntax:
public object this[string columnName] {get; set;}

To use this property, pass the object name of the column in the square
brackets. Here are examples:
using System;
using System.IO;
using System.Data;

namespace VideoCollection
{
public static class Program
{
. . . No Change

C# 3.0 Practical Learning II 239


static void ShowVideos()
{
dsVideos.ReadXml(strDirectory + @"\videos.xml");

Console.WriteLine("================================");
Console.WriteLine("Video Collection");

Console.WriteLine("================================");
for (int i = 0; i < tblVideos.Rows.Count; i++)
{
DataRow row = tblVideos.Rows[i];
Console.WriteLine("Shelf #: {0}",
tblVideos.Rows[i][colShelfNumber]);
Console.WriteLine("Title: {0}",
tblVideos.Rows[i][colTitle]);
Console.WriteLine("Director: {0}",
tblVideos.Rows[i][colDirector]);
Console.WriteLine("Length: {0}",
tblVideos.Rows[i][colLength]);
Console.WriteLine("Year: {0}",
tblVideos.Rows[i][colYear]);
Console.WriteLine("Rating: {0}",
tblVideos.Rows[i][colRating]);

Console.WriteLine("--------------------------------");
}
}

static int Main(string[] args)


{
CreateCollection();
ShowVideos();

return 0;
}
}
}

Instead of using the index of a column, you can also locate a value using the
variable name of its column. To do this, you can use the following syntax of
the DataRow indexed property:
public object this[DataColumn column] {get; set;}

This property expects the object name of the column passed in its square
brackets. We saw earlier how to use this version of the property. Here are
examples, using foreach:
using System;
using System.IO;
using System.Data;

namespace VideoCollection
{

C# 3.0 Practical Learning II 240


public static class Program
{
. . . No Change

static void ShowVideos()


{
dsVideos.ReadXml(strDirectory + @"\videos.xml");

Console.WriteLine("================================");
Console.WriteLine("Video Collection");

Console.WriteLine("================================");
foreach (DataRow row in tblVideos.Rows)
{
Console.WriteLine("Shelf #: {0}",
row["ShelfNumber"]);
Console.WriteLine("Title: {0}",
row["Title"]);
Console.WriteLine("Director: {0}",
row["Director"]);
Console.WriteLine("Length: {0}",
row["Length"]);
Console.WriteLine("Year: {0}", row["Year"]);
Console.WriteLine("Rating: {0}",
row["Rating"]);

Console.WriteLine("--------------------------------");
}
}

static int Main(string[] args)


{
CreateCollection();
ShowVideos();

return 0;
}
}
}

The third option you have is to identify the column by its index. To do this,
use the following syntax of the DataRow indexed property:
public object this[int columnIndex] {get; set;}

This property expects the index of the column.

 Here are examples using the for loop:


using System;
using System.IO;
using System.Data;

namespace VideoCollection
{

C# 3.0 Practical Learning II 241


public static class Program
{
. . . No Change

static void ShowVideos()


{
dsVideos.ReadXml(strDirectory + @"\videos.xml");

Console.WriteLine("================================");
Console.WriteLine("Video Collection");

Console.WriteLine("================================");
for (int i = 0; i < tblVideos.Rows.Count; i++)
{
DataRow row = tblVideos.Rows[i];
Console.WriteLine("Shelf #: {0}",
tblVideos.Rows[i][0]);
Console.WriteLine("Title: {0}",
tblVideos.Rows[i][1]);
Console.WriteLine("Director: {0}",
tblVideos.Rows[i][2]);
Console.WriteLine("Length: {0}",
tblVideos.Rows[i][3]);
Console.WriteLine("Year: {0}",
tblVideos.Rows[i][4]);
Console.WriteLine("Rating: {0}",
tblVideos.Rows[i][5]);

Console.WriteLine("--------------------------------");
}
}

static int Main(string[] args)


{
CreateCollection();
ShowVideos();

return 0;
}
}
}

Or, here are examples using foreach:


using System;
using System.IO;
using System.Data;

namespace VideoCollection
{
public static class Program
{
. . . No Change

static void ShowVideos()

C# 3.0 Practical Learning II 242


{
dsVideos.ReadXml(strDirectory + @"\videos.xml");

Console.WriteLine("================================");
Console.WriteLine("Video Collection");

Console.WriteLine("================================");
foreach (DataRow row in tblVideos.Rows)
{
Console.WriteLine("Shelf #: {0}", row[0]);
Console.WriteLine("Title: {0}", row[1]);
Console.WriteLine("Director: {0}", row[2]);
Console.WriteLine("Length: {0}", row[3]);
Console.WriteLine("Year: {0}", row[4]);
Console.WriteLine("Rating: {0}", row[5]);

Console.WriteLine("--------------------------------");
}
}

static int Main(string[] args)


{
CreateCollection();
ShowVideos();

return 0;
}
}
}

Practical Learning: Getting the Values of a Data Set

1. Access the Inventory.cs file

2. To allow the user to display the store inventory, change the file as
follows:
 
using System;
using System.IO;
using System.Xml;
using System.Data;

namespace CollegeParkAutoParts1
{
public class Inventory
{
// These are the columns of the AutoParts table
private DataColumn colPartNumber;
private DataColumn colYear;

C# 3.0 Practical Learning II 243


private DataColumn colMake;
private DataColumn colModel;
private DataColumn colPartName;
private DataColumn colPartPrice;

// These are the columns of the StoreItems table


private DataColumn colItemNumber;
private DataColumn colItemName;
private DataColumn colItemPrice;

// These are the table of the CollegeParkAutoParts


database
private DataTable tblAutoParts;
private DataTable tblStoreItems;

// This is the database


private DataSet dsStoreItems;

// These are accessory strings


string strDirectory;
string strFilename;

// This default constructor is used to create


// the structures of the tables
public Inventory()
{
colPartNumber = new DataColumn("PartNumber",
Type.GetType("System.Int32"));
colYear = new DataColumn("Year",
Type.GetType("System.Int32"));
colMake = new DataColumn("Make",
Type.GetType("System.String"));
colModel = new DataColumn("Model",
Type.GetType("System.String"));
colPartName = new DataColumn("PartName",
Type.GetType("System.String"));
colPartPrice = new DataColumn("PartPrice",
Type.GetType("System.Double"));

tblAutoParts = new DataTable("AutoPart");


tblAutoParts.Columns.Add(colPartNumber);
tblAutoParts.Columns.Add(colYear);
tblAutoParts.Columns.Add(colMake);
tblAutoParts.Columns.Add(colModel);
tblAutoParts.Columns.Add(colPartName);
tblAutoParts.Columns.Add(colPartPrice);

tblStoreItems = new DataTable("StoreItem");


colItemNumber = new DataColumn("ItemNumber",
Type.GetType("System.Int32"));
colItemName = new DataColumn("ItemName",
Type.GetType("System.String"));
colItemPrice = new DataColumn("ItemPrice",
Type.GetType("System.Double"));
tblStoreItems .Columns.Add(colItemNumber);
tblStoreItems.Columns.Add(colItemName);

C# 3.0 Practical Learning II 244


tblStoreItems.Columns.Add(colItemPrice);

dsStoreItems = new DataSet("StoreItems");


dsStoreItems.Tables.Add(tblAutoParts);
dsStoreItems.Tables.Add(tblStoreItems);

// This database will use a folder


// named College Park Auto Parts
// and located on the C: drive
strDirectory = @"C:\College Park Auto Parts";
strFilename = strDirectory + "\\" +
"StoreItems.xml";

DirectoryInfo dirInfo = new


DirectoryInfo(strDirectory);

// If the folder doesn't exist already, create it


if (!dirInfo.Exists)
dirInfo.Create();
}

// This method guides the user in creating a new store


item
public void CreateStoreItem()
{
// Accessory variables
int year = 1960;
int iPartNumber = 0, iItemNumber = 0;
double unitPrice = 0.00D;
string strMake = "Unknown", strModel = "Unknown",
strPartName = "N/A", strItemName = "N/A";
int typeOfItem = 0;
char ansAdd = 'n';

// If the StoreItems.xml file exists already, then


open it
if (File.Exists(strFilename))
dsStoreItems.ReadXml(strFilename);

// This do...while is used in case the user wants to


// repeatedly perform these actions
do
{
try
{
// Find out what the user wants to do
Console.WriteLine("What type of item do you
want to add");
Console.WriteLine("1. An auto part (for a
car or an engine)");
Console.WriteLine("2. Another type of item,
not for a specific car");
Console.WriteLine("0. Stop");
Console.WriteLine("Enter the following
pieces of information");
Console.Write("Your Choice: ");

C# 3.0 Practical Learning II 245


typeOfItem = int.Parse(Console.ReadLine());

// The user wants to add a new car part


if (typeOfItem == 1)
{
// Create a random number of 6 digits
Random rndPartNumber = new Random();
iPartNumber = rndPartNumber.Next(100000,
999999);

// Request the information about the car


and the part
try
{
Console.Write("Car Year: ");
year =
int.Parse(Console.ReadLine());
}
catch (FormatException)
{
Console.WriteLine("Invalid year");
}
Console.Write("Make (or None if N/A):
");
strMake = Console.ReadLine();
Console.Write("Model (or None if N/A):
");
strModel = Console.ReadLine();
Console.Write("Part Name:
");
strPartName = Console.ReadLine();

try
{
Console.Write("Unit Price:
");
unitPrice =
double.Parse(Console.ReadLine());
}
catch (FormatException)
{
Console.WriteLine("Invalid unit
price");
}

// Present the user with a summary of


the part to be added
// This is a safe guard for a console
application so that
// if the user made a mistake, he or she
can dismiss it
// instead of adding a part with wrong
information
Console.WriteLine("\nHere is a summary
of the part to be added");

C# 3.0 Practical Learning II 246


Console.WriteLine("--------------------------------");
Console.WriteLine("Part Number: {0}",
iPartNumber);
Console.WriteLine("Year: {0}",
year);
Console.WriteLine("Make: {0}",
strMake);
Console.WriteLine("Model: {0}",
strModel);
Console.WriteLine("Part Name: {0}",
strPartName);
Console.WriteLine("Unit Price: {0:C}",
unitPrice);

Console.WriteLine("--------------------------------");

Console.Write("Are you ready to add it


to the database (y/n)? ");
ansAdd = char.Parse(Console.ReadLine());

// If the user has decided to add the


part to the database,
// then add it
if ((ansAdd == 'y') || (ansAdd == 'Y'))
{
DataRow part =
tblAutoParts.NewRow();
part["PartNumber"] = iPartNumber;
part["Year"] = year;
part["Make"] = strMake;
part["Model"] = strModel;
part["PartName"] = strPartName;
part["PartPrice"] = unitPrice;
tblAutoParts.Rows.Add(part);

dsStoreItems.WriteXml(strFilename);
}
else
Console.WriteLine("The part will not
be added to the database");
}
// For the same logic for other store items
// The items in this section can be anything
else if (typeOfItem == 2)
{
Random rndPartNumber = new Random();
iItemNumber = rndPartNumber.Next(100000,
999999);

Console.Write("Item/Description: ");
strItemName = Console.ReadLine();

try
{

C# 3.0 Practical Learning II 247


Console.Write("Unit Price:
");
unitPrice =
double.Parse(Console.ReadLine());
}
catch (FormatException)
{
Console.WriteLine("Invalid unit
price");
}

Console.WriteLine("\nHere is a summary
of the part to be added");

Console.WriteLine("--------------------------------");
Console.WriteLine("Item Number: {0}",
iItemNumber);
Console.WriteLine("Name/Descr: {0}",
strItemName);
Console.WriteLine("Unit Price: {0:C}",
unitPrice);

Console.WriteLine("--------------------------------");

Console.Write("Are you ready to add it


to the database (y/n)? ");
ansAdd = char.Parse(Console.ReadLine());

if ((ansAdd == 'y') || (ansAdd == 'Y'))


{
DataRow item =
tblStoreItems.NewRow();
item["ItemNumber"] = iItemNumber;
item["ItemName"] = strItemName;
item["ItemPrice"] = unitPrice;
tblStoreItems.Rows.Add(item);

dsStoreItems.WriteXml(strFilename);
}
else
Console.WriteLine("The part will not
be added to the database");
}
}
catch (FormatException)
{
Console.WriteLine("Invalid Menu Selection");
}
} while (typeOfItem == 1 || typeOfItem == 2);
}

// This method is used to display the store inventory of


all items
public void ShowInventory()
{
if (File.Exists(strFilename))

C# 3.0 Practical Learning II 248


{
dsStoreItems.ReadXml(strFilename);

Console.WriteLine("================================");
Console.WriteLine(" College Park Auto Parts");
Console.WriteLine(" Store Inventory");
Console.WriteLine(" Car Parts");

Console.WriteLine("================================");
foreach (DataRow part in tblAutoParts.Rows)
{
Console.WriteLine("Part #: {0}",
part["PartNumber"]);
Console.WriteLine("Car Year: {0}",
part["Year"]);
Console.WriteLine("Make: {0}",
part["Make"]);
Console.WriteLine("Model: {0}",
part["Model"]);
Console.WriteLine("Part Name: {0}",
part["PartName"]);
Console.WriteLine("Unit Price: {0:C}",
part["PartPrice"]);

Console.WriteLine("--------------------------------");
}

Console.WriteLine("================================");
Console.WriteLine(" Other Store Items");

Console.WriteLine("================================");
foreach (DataRow item in tblStoreItems.Rows)
{
Console.WriteLine("Item #: {0}",
item["ItemNumber"]);
Console.WriteLine("Name/Description: {0}",
item["ItemName"]);
Console.WriteLine("Unit Price: {0:C}",
item["ItemPrice"]);

Console.WriteLine("--------------------------------");
}
}
}
}
}

3. Access the Program.cs file

4. To allow the user to decide about the action to take when the application
comes up, change the file as follows:
 
using System;

C# 3.0 Practical Learning II 249


namespace CollegeParkAutoParts1
{
class Program
{
static int Main(string[] args)
{
char choice = '0';
Inventory inv = new Inventory();

Console.WriteLine("================================");
Console.WriteLine(" College Park Auto Parts");

Console.WriteLine("================================");
do
{
try
{
Console.WriteLine("What do you want to
do?");
Console.WriteLine("1. Add New Store Item");
Console.WriteLine("2. View Inventory");
Console.WriteLine("0. Quit");
Console.Write("Your Selection? ");
choice = char.Parse(Console.ReadLine());

if (choice == '1')
inv.CreateStoreItem();
else if (choice == '2')
inv.ShowInventory();
}
catch (FormatException)
{
Console.WriteLine("Unrecognizable Menu
Selection");
}
} while ((choice == '1') || (choice == '2'));

Console.WriteLine();
return 0;
}
}
}

5. Execute the application to see the result:


 
=====================================
College Park Auto Parts
=====================================
What do you want to do?
1. Add New Store Item
2. View Inventory
0. Quit
Your Selection? 2

C# 3.0 Practical Learning II 250


==========================================
College Park Auto Parts
Store Inventory
Car Parts
==========================================
Part #: 299693
Car Year: 2005
Make: Acura
Model: NSX 3.0L V6
Part Name: Oil Filter
Unit Price: $8.85
------------------------------------------
Part #: 398747
Car Year: 2002
Make: Audi
Model: Quattro 1.8L Turbo
Part Name: Clash Bear
Unit Price: $55.50
------------------------------------------
Part #: 174724
Car Year: 2002
Make: BMW
Model: 325i 2.5L L6
Part Name: Ignition Coil
Unit Price: $60.85
------------------------------------------
==========================================
Other Store Items
==========================================
Item #: 319027
Name/Description: Soda 2L Bottle
Unit Price: $1.75
------------------------------------------
Item #: 865745
Name/Description: STP Gas Treatment 3-Pack
Unit Price: $2.99
------------------------------------------
What do you want to do?
1. Add New Store Item
2. View Inventory
0. Quit
Your Selection? 0

Press any key to continue . . .

6. Close the DOS window

C# 3.0 Practical Learning II 251


Records Management
 

Records Maintenance
 

Introduction

Once a table has been filled with records, you can perform maintenance
operations on it such as changing some records or removing others.

Editing a record consists of changing one of the values of the record under a
particular column. There are various ways you can do this. For a console
application, the general steps you can (we will) follow are:

1. Make sure the table has at least one column that can be used to
uniquely identify each record. For example, when creating a table for
employees, you can assign a unique employee number to each staff member.
The same would go for students. If you are creating a table for a collection of
items, such as a book or a video collection, a commercial store that sells items
such as auto parts, make sure each item has a certain value that is unique to it,
such as a shelf number or a store number

2. Before editing a record, make the user aware of the existing values. You
can do this by displaying the records of the database

3. Request a value of the unique column from the user. For a table that
contains employees information, you can ask the user to enter the employee
number of the record to edit. The same would be for a book or video collection,
a commercial store that sells items, etc

4. After the user has indicated the record that will be modified, display the
particular values of that record

5. Asks the user to specify what particular column will receive the change

6. Request the new value from the user

7. After the user has entered the new value, change it

8. To finalize the record edition, save the row

To perform these steps, you use a combination of the techniques we has


reviewed so far: locate the table, display the records, locate the record, locate

C# 3.0 Practical Learning II 252


the column, assign the value to the column of a record, save the table.

Editing a Record by the Columns' Object Names

In the previous lesson, we saw that you could isolate a record based on the
object names of the columns such as Director or Title for a table of videos.
Once you have identified a column for a record, you can assign the desired
value. Here are examples:
using System;
using System.IO;
using System.Xml;
using System.Data;
using System.Collections;

namespace VideoCollection3
{
public class VideoCollection
{
public DataSet dsVideos;

private DataColumn colShelfNumber;


private DataColumn colTitle;
private DataColumn colDirector;
private DataColumn colYear;
private DataColumn colLength;
private DataColumn colRating;
private DataTable tblVideos;

// These are accessory strings


string strDirectory;
string strFilename;

public VideoCollection()
{
CreateCollection();
strDirectory = @"C:\Programs\Video Collection";
strFilename = strDirectory + "\\" + "videos.xml";

DirectoryInfo dirInfo = new


DirectoryInfo(strDirectory);

// If the folder doesn't exist already, create it


if (!dirInfo.Exists)
dirInfo.Create();
}

public void CreateCollection()


{
dsVideos = new DataSet("Videos");

tblVideos = new DataTable("Video");

colShelfNumber = new DataColumn("ShelfNumber",

C# 3.0 Practical Learning II 253


Type.GetType("System.String"));
tblVideos.Columns.Add(colShelfNumber);

colTitle = new DataColumn("Title",


Type.GetType("System.String"));
tblVideos.Columns.Add(colTitle);

colDirector = new DataColumn("Director",


Type.GetType("System.String"));
tblVideos.Columns.Add(colDirector);

colYear = new DataColumn("Year",


Type.GetType("System.Int32"));
tblVideos.Columns.Add(colYear);

colLength = new DataColumn("Length",


Type.GetType("System.String"));
tblVideos.Columns.Add(colLength);

colRating = new DataColumn("Rating",


Type.GetType("System.String"));
tblVideos.Columns.Add(colRating);

dsVideos.Tables.Add(tblVideos);
}

public void ShowTables()


{
int i = 1;

Console.WriteLine("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=");
Console.WriteLine("Video Collection - Tables");
Console.WriteLine("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=");

foreach (DataTable tbl in dsVideos.Tables)


Console.WriteLine("{0}. {1}", i++,
tbl.TableName);
Console.WriteLine("----------------------------");
}

public void ShowColumns(string table)


{
int i = 1;
DataTable tbl = dsVideos.Tables[table];

Console.WriteLine("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=");
Console.WriteLine("Video Collection - {0} Columns",
table);
Console.WriteLine("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=");

foreach (DataColumn col in tbl.Columns)


Console.WriteLine("{0}. {1}", i++,
col.ColumnName);
Console.WriteLine("----------------------------");
}

C# 3.0 Practical Learning II 254


public void CreateVideo()
{
string ShelfNumber, Title, Director, Length;
int Year;
string Rating;

Console.WriteLine(
"Enter the following pieces of information about
the video");
Console.Write("Shelf Number: ");
ShelfNumber = Console.ReadLine();

XmlDocument xmlVideos = new XmlDocument();

if (File.Exists(strFilename))
{
xmlVideos.Load(strFilename);
dsVideos.ReadXml(strFilename);

XmlElement nodRoot = xmlVideos.DocumentElement;


XmlNodeList nodShelfNumbers =
nodRoot.GetElementsByTagName("ShelfNumber");

foreach (XmlNode nodShelfNumber in


nodShelfNumbers)
{
if (nodShelfNumber.InnerText == ShelfNumber)
{
Console.WriteLine("The shelf number {0}
exists already",
ShelfNumber);
return;
}
}
}
else
dsVideos.WriteXml(strFilename);

Console.Write("Title: ");
Title = Console.ReadLine();
Console.Write("Director: ");
Director = Console.ReadLine();
Console.Write("Year Released: ");
Year = int.Parse(Console.ReadLine());
Console.Write("Length (ex 118mins): ");
Length = Console.ReadLine();

Console.WriteLine("Specify corresponding rating");


Console.WriteLine("G");
Console.WriteLine("PG");
Console.WriteLine("PG-13");
Console.WriteLine("R");
Console.WriteLine("NC-17");
Console.WriteLine("N/R");
Console.Write("Your Choice? ");
Rating = Console.ReadLine();

C# 3.0 Practical Learning II 255


DataRow rowVideo = this.tblVideos.NewRow();
rowVideo[0] = ShelfNumber;
rowVideo[1] = Title;
rowVideo[2] = Director;
rowVideo[3] = Year;
rowVideo[4] = Length;
rowVideo[5] = Rating;

this.tblVideos.Rows.Add(rowVideo);
this.dsVideos.WriteXml(strFilename);
}

public void ShowVideos()


{
if (File.Exists(strFilename))
{
dsVideos.ReadXml(strFilename);

Console.WriteLine("========================================");
Console.WriteLine(" Video Collection");

Console.WriteLine("=========================================");
foreach (DataRow vdo in tblVideos.Rows)
{
Console.WriteLine("Shelf #: {0}",
vdo["ShelfNumber"]);
Console.WriteLine("Title: {0}",
vdo["Title"]);
Console.WriteLine("Director: {0}",
vdo["Director"]);
Console.WriteLine("(c) Year: {0}",
vdo["Year"]);
Console.WriteLine("Length: {0:C}",
vdo["Length"]);
Console.WriteLine("Rating: {0}",
vdo["Rating"]);

Console.WriteLine("-----------------------------------------");
}
}
}

public void EditVideo()


{
if (File.Exists(strFilename))
{
bool found = false;
int iYear = 0;
string strShelfNumber = "AA-000",
strTitle = "Unknown",
strDirector = "Unknown",
strLength = "N/A",
strRating = "N/A";

C# 3.0 Practical Learning II 256


dsVideos.ReadXml(strFilename);
DataRow rowVideo = null;

Console.WriteLine("\nHere is the current list of


videos");

Console.WriteLine("========================================");
Console.WriteLine(" Video Collection");

Console.WriteLine("=========================================");
foreach (DataRow vdo in tblVideos.Rows)
{
Console.WriteLine("Shelf #: {0}",
vdo["ShelfNumber"]);
Console.WriteLine("Title: {0}",
vdo["Title"]);
Console.WriteLine("Director: {0}",
vdo["Director"]);
Console.WriteLine("(c) Year: {0}",
vdo["Year"]);
Console.WriteLine("Length: {0:C}",
vdo["Length"]);
Console.WriteLine("Rating: {0}",
vdo["Rating"]);

Console.WriteLine("-----------------------------------------");
}

Console.Write("Enter the shelf number of the


video you want to edit: ");
strShelfNumber = Console.ReadLine();

foreach (DataRow vdo in tblVideos.Rows)


{
string str = (string)vdo["ShelfNumber"];

Console.WriteLine(str);
if( str == strShelfNumber )
{
//rowVideo = vdo;
found = true;

Console.WriteLine("\n-----------------------------------------")
;
Console.WriteLine("Here is the video");
Console.WriteLine("1. Title: {0}",
vdo["Title"]);
Console.WriteLine("2. Director: {0}",
vdo["Director"]);
Console.WriteLine("3. (c) Year: {0}",
vdo["Year"]);
Console.WriteLine("4. Length: {0}",
vdo["Length"]);
Console.WriteLine("5. Rating: {0}",

C# 3.0 Practical Learning II 257


vdo["Rating"]);

Console.WriteLine("-----------------------------------------");

strTitle = (string)vdo["Title"];
strDirector = (string)vdo["Director"];
iYear = (int)vdo["Year"];
strLength = (string)vdo["Length"];
strRating = (string)vdo["Rating"];

Console.Write("Enter the index of the


column " +
"whose value you want to
change: ");
int col = int.Parse(Console.ReadLine());

switch (col)
{
case 1:
vdo["ShelfNumber"] =
strShelfNumber;
Console.Write("Enter the new
video title: ");
strTitle = Console.ReadLine();
vdo["Title"] = strTitle;
vdo["Director"] = strDirector;
vdo["Year"] = iYear;
vdo["Length"] = strLength;
vdo["Rating"] = strRating;

this.dsVideos.WriteXml(strFilename);
break;

case 2:
vdo["ShelfNumber"] =
strShelfNumber;
vdo["Title"] = strTitle;
Console.Write("Enter the new
director of the video: ");
strDirector =
Console.ReadLine();
vdo["Director"] = strDirector;
vdo["Year"] = iYear;
vdo["Length"] = strLength;
vdo["Rating"] = strRating;

this.dsVideos.WriteXml(strFilename);
break;

case 3:
vdo["ShelfNumber"] =
strShelfNumber;
vdo["Title"] = strTitle;
vdo["Director"] = strDirector;
Console.Write("Enter the right year
released of the video: ");

C# 3.0 Practical Learning II 258


iYear =
int.Parse( Console.ReadLine());
vdo["Year"] = iYear;
vdo["Length"] = strLength;
vdo["Rating"] = strRating;

this.dsVideos.WriteXml(strFilename);
break;

case 4:
vdo["ShelfNumber"] =
strShelfNumber;
vdo["Title"] = strTitle;
vdo["Director"] = strDirector;
vdo["Year"] = iYear;
Console.Write("Enter the new
length of the video: ");
strLength = Console.ReadLine();
vdo["Length"] = strLength;
vdo["Rating"] = strRating;

this.dsVideos.WriteXml(strFilename);
break;

case 5:
vdo["ShelfNumber"] =
strShelfNumber;
vdo["Title"] = strTitle;
vdo["Director"] = strDirector;
vdo["Year"] = iYear;
vdo["Length"] = strLength;
Console.Write("Enter the right
rating for the video: ");
strRating = Console.ReadLine();
vdo["Rating"] = strRating;

this.dsVideos.WriteXml(strFilename);
break;
}
return;
}
}

if (found == false)
{
Console.WriteLine("No video with that shelf
number was found");
return;
}
}
}
}
}

Editing a Record by the Columns' Indices

C# 3.0 Practical Learning II 259


We saw that another technique of recognizing a record was by using the index
of each column applied to the DataRow object of the record. You can apply this
concept to identify each column. Once you do, you can then assign the desired
value.

Deleting Records
 

Deleting the Current Row

If you happen to have a record you don't need or don't find necessary in a
table, you can remove that record from the table. To start, you must establish
what record you want to delete. Once again, you would need a way to uniquely
identify a record. For our video collection, you can use the shelf number
column. Once you have located the undesired record, you can delete it.

To assist you with removing a record, the DataRow class is equipped with a
method named Delete. Its syntax is simply:
public void Delete();

This method must be called by the record that wants to be deleted. Here is an
example:

using System;
using System.IO;
using System.Xml;
using System.Data;
using System.Collections;

namespace VideoCollection3
{
public class VideoCollection
{

. . . No Change

public void DeleteVideo()


{
if (File.Exists(strFilename))
{
bool found = false;
string strShelfNumber = "AA-000";

dsVideos.ReadXml(strFilename);

Console.WriteLine("\nHere is the current list of


videos");

C# 3.0 Practical Learning II 260


Console.WriteLine("========================================");
Console.WriteLine(" Video Collection");

Console.WriteLine("=========================================");
foreach (DataRow vdo in tblVideos.Rows)
{
Console.WriteLine("Shelf #: {0}",
vdo["ShelfNumber"]);
Console.WriteLine("Title: {0}",
vdo["Title"]);
Console.WriteLine("Director: {0}",
vdo["Director"]);
Console.WriteLine("(c) Year: {0}",
vdo["Year"]);
Console.WriteLine("Length: {0:C}",
vdo["Length"]);
Console.WriteLine("Rating: {0}",
vdo["Rating"]);

Console.WriteLine("-----------------------------------------");
}

Console.Write("Enter the shelf number of the video


you want to delete: ");
strShelfNumber = Console.ReadLine();

foreach (DataRow vdo in tblVideos.Rows)


{
string str = (string)vdo["ShelfNumber"];

if (str == strShelfNumber)
{
found = true;

Console.WriteLine("\n-----------------------------------------")
;
Console.WriteLine("Here is the video you
want to delete");
Console.WriteLine("1. Title: {0}",
vdo["Title"]);
Console.WriteLine("2. Director: {0}",
vdo["Director"]);
Console.WriteLine("3. (c) Year: {0}",
vdo["Year"]);
Console.WriteLine("4. Length: {0}",
vdo["Length"]);
Console.WriteLine("5. Rating: {0}",
vdo["Rating"]);

Console.WriteLine("-----------------------------------------");

Console.Write("Do you still want to


delete this video (y/n)? ");
char ans =

C# 3.0 Practical Learning II 261


char.Parse(Console.ReadLine());

if ((ans == 'y') || (ans == 'Y'))


{
vdo.Delete();
dsVideos.WriteXml(strFilename);
Console.WriteLine("The video has
been deleted!");
}

return;
}
}

if (found == false)
{
Console.WriteLine("No video with that shelf
number was found");
return;
}
}
}
}
}

Removing a Row From the Collection of Records

Besides the DataRow class, the DataRowCollection class provides its own
means of deleting a record from a table. To delete a record, you can call the
DataRowCollection.Remove() method. Its syntax is:

public void Remove(DataRow row);

This method takes as argument a DataRow object and checks whether the table
contains it. If that record exists, it gets deleted, including all of its entries for
each column. Here is an example:
using System;
using System.IO;
using System.Xml;
using System.Data;
using System.Collections;

namespace VideoCollection3
{
public class VideoCollection
{

. . . No Change

public void DeleteVideo()


{
if (File.Exists(strFilename))
{

C# 3.0 Practical Learning II 262


bool found = false;
string strShelfNumber = "AA-000";

dsVideos.ReadXml(strFilename);

Console.WriteLine("\nHere is the current list of


videos");

Console.WriteLine("========================================");
Console.WriteLine(" Video Collection");

Console.WriteLine("=========================================");
foreach (DataRow vdo in tblVideos.Rows)
{
Console.WriteLine("Shelf #: {0}",
vdo["ShelfNumber"]);
Console.WriteLine("Title: {0}",
vdo["Title"]);
Console.WriteLine("Director: {0}",
vdo["Director"]);
Console.WriteLine("(c) Year: {0}",
vdo["Year"]);
Console.WriteLine("Length: {0:C}",
vdo["Length"]);
Console.WriteLine("Rating: {0}",
vdo["Rating"]);

Console.WriteLine("-----------------------------------------");
}

Console.Write("Enter the shelf number of the video


you want to delete: ");
strShelfNumber = Console.ReadLine();

foreach (DataRow vdo in tblVideos.Rows)


{
string str = (string)vdo["ShelfNumber"];

if (str == strShelfNumber)
{
found = true;

Console.WriteLine("\n-----------------------------------------")
;
Console.WriteLine("Here is the video you
want to delete");
Console.WriteLine("1. Title: {0}",
vdo["Title"]);
Console.WriteLine("2. Director: {0}",
vdo["Director"]);
Console.WriteLine("3. (c) Year: {0}",
vdo["Year"]);
Console.WriteLine("4. Length: {0}",
vdo["Length"]);

C# 3.0 Practical Learning II 263


Console.WriteLine("5. Rating: {0}",
vdo["Rating"]);

Console.WriteLine("-----------------------------------------");

Console.Write("Do you still want to


delete this video (y/n)? ");
char ans =
char.Parse(Console.ReadLine());

if ((ans == 'y') || (ans == 'Y'))


{
tblVideos.Rows.Remove(vdo);
dsVideos.WriteXml(strFilename);
Console.WriteLine("The video has
been deleted!");
}

return;
}
}

if (found == false)
{
Console.WriteLine("No video with that shelf
number was found");
return;
}
}
}
}
}

Deleting a Record by its Index

When calling the DataRowCollection.Remove() method, you must pass an


exact identification of the record. If you don't have that identification, you can
delete a record based on its index. To do this, you would call the
DataRowCollection.RemoveAt() method. Its syntax is:

public void RemoveAt(int index);

This method takes as argument the index of the record you want to delete. If a
record with that index exists, it would be deleted.

Deleting all Records of a Table

To delete all records of a table, call the DataRowCollection.Clear() method.


Its syntax is:
public void Clear();

This method is used to clear the table of all records.

C# 3.0 Practical Learning II 264


Data Relationships
 

Introduction

In the database world, a relationship is a link that exists between two objects,
mainly tables, so that data can flow from one object to another. A relationship
can do even more than that: it can be used to check the accuracy of
information from one object to another, it can be used to update the
information in one object when related information in another object has been
changed.

Remember that whenever you are dealing with a group of records, also called a
set of records, or a set of data, or a data set, you need an object that can
"translate" the values of your records into values that are data-oriented. The
object used to take care of this aspect is implemented through the DataSet
class. In this case, since we want to address relationships among tables, we will
need a data set object to manage such links.

Table Preparation

Imagine that you are creating a list of employees in a mid-size to large company
and want to categorize them by their employment status. You can start by creating
a list of the employees:

First Name Last Name Department

Peter Larsen Accounting

Paul Banack IT/IM

Helene Cassavoy Accounting

Anselme Thomas Public Relations

Bertha Um Corporate

This is a classic table. There are two common ways you can create a table. You
can generate a table from a database, or you can use the DataTable class that
allows you to manually create a table. Here is an example:
using System;
using System.Xml;

C# 3.0 Practical Learning II 265


using System.Data;

class Exercise
{
static void Main()
{
DataSet dsEmployment = new DataSet();
DataTable dtEmployees = new DataTable("Employees");

DataColumn[] dcEmployees = new DataColumn[3];

dcEmployees[0] = new DataColumn("FirstName",


System.Type.GetType("System.String"));
dtEmployees.Columns.Add(dcEmployees[0]);
dcEmployees[1] = new DataColumn("LastName",
System.Type.GetType("System.String"));
dtEmployees.Columns.Add(dcEmployees[1]);
dcEmployees[2] = new DataColumn("Department",
System.Type.GetType("System.String"));
dtEmployees.Columns.Add(dcEmployees[2]);

DataRow drEmplRecord = dtEmployees.NewRow();


drEmplRecord["FirstName"] = "Peter";
drEmplRecord["LastName"] = "Larsen";
drEmplRecord["Department"] = "Accounting";
dtEmployees.Rows.Add(drEmplRecord);

drEmplRecord = dtEmployees.NewRow();
drEmplRecord["FirstName"] = "Paul";
drEmplRecord["LastName"] = "Banack";
drEmplRecord["Department"] = "IT/IM";
dtEmployees.Rows.Add(drEmplRecord);

drEmplRecord = dtEmployees.NewRow();
drEmplRecord["FirstName"] = "Helene";
drEmplRecord["LastName"] = "Casson";
drEmplRecord["Department"] = "Accounting";
dtEmployees.Rows.Add(drEmplRecord);

drEmplRecord = dtEmployees.NewRow();
drEmplRecord["FirstName"] = "Anselme";
drEmplRecord["LastName"] = "Thomas";
drEmplRecord["Department"] = "Public Rel";
dtEmployees.Rows.Add(drEmplRecord);

drEmplRecord = dtEmployees.NewRow();
drEmplRecord["FirstName"] = "Bertha";
drEmplRecord["LastName"] = "Colson";
drEmplRecord["Department"] = "Corporate";
dtEmployees.Rows.Add(drEmplRecord);

dsEmployment.Tables.Add(dtEmployees);

Console.WriteLine("============+===============+==============="
);

C# 3.0 Practical Learning II 266


Console.WriteLine("First Name | Last Name |
Department");
Console.WriteLine("------------+---------------
+---------------");
foreach(DataRow row in
dsEmployment.Tables["Employees"].Rows)
{
Console.WriteLine("{0}\t | {1}\t |
{2}",
row["FirstName"],
row["LastName"],
row["Department"]);
}

Console.WriteLine("============+===============+===============\
n");
}
}

This would produce:


============+===============+===============
First Name | Last Name | Department
------------+---------------+---------------
Peter | Larsen | Accounting
Paul | Banack | IT/IM
Helene | Casson | Accounting
Anselme | Thomas | Public Rel
Bertha | Colson | Corporate
============+===============+===============

Press any key to continue . . .

To associate each employee with a department, you can first create a table for
the departments. Here is an example:
using System;
using System.Xml;
using System.Data;

class Exercise
{
static void Main()
{
DataSet dsEmployment = new DataSet();
DataTable dtEmployees = new
DataTable("Employees");

DataColumn[] dcEmployees = new DataColumn[3];

dcEmployees[0] = new DataColumn("FirstName",

System.Type.GetType("System.String"));
dtEmployees.Columns.Add(dcEmployees[0]);
dcEmployees[1] = new DataColumn("LastName",

C# 3.0 Practical Learning II 267


System.Type.GetType("System.String"));
dtEmployees.Columns.Add(dcEmployees[1]);
dcEmployees[2] = new DataColumn("Department",

System.Type.GetType("System.String"));
dtEmployees.Columns.Add(dcEmployees[2]);

DataRow drEmplRecord = dtEmployees.NewRow();


drEmplRecord["FirstName"] = "Peter";
drEmplRecord["LastName"] = "Larsen";
drEmplRecord["Department"] = "Accounting";
dtEmployees.Rows.Add(drEmplRecord);

drEmplRecord = dtEmployees.NewRow();
drEmplRecord["FirstName"] = "Paul";
drEmplRecord["LastName"] = "Banack";
drEmplRecord["Department"] = "IT/IM";
dtEmployees.Rows.Add(drEmplRecord);

drEmplRecord = dtEmployees.NewRow();
drEmplRecord["FirstName"] = "Helene";
drEmplRecord["LastName"] = "Casson";
drEmplRecord["Department"] = "Accounting";
dtEmployees.Rows.Add(drEmplRecord);

drEmplRecord = dtEmployees.NewRow();
drEmplRecord["FirstName"] = "Anselme";
drEmplRecord["LastName"] = "Thoma";
drEmplRecord["Department"] = "Public Relations";
dtEmployees.Rows.Add(drEmplRecord);

drEmplRecord = dtEmployees.NewRow();
drEmplRecord["FirstName"] = "Bertha";
drEmplRecord["LastName"] = "Um";
drEmplRecord["Department"] = "Corporate";
dtEmployees.Rows.Add(drEmplRecord);

DataTable dtEmplStatus = new


DataTable("EmploymentStatus");

DataColumn dcEmployment = new DataColumn();


dcEmployment = new DataColumn("EmplStatus",

System.Type.GetType("System.String"));
dtEmplStatus.Columns.Add(dcEmployment);

DataRow drEmployment = dtEmplStatus.NewRow();


drEmployment["EmplStatus"] = "Full Time";
dtEmplStatus.Rows.Add(drEmployment);

drEmployment = dtEmplStatus.NewRow();
drEmployment["EmplStatus"] = "Part Time";
dtEmplStatus.Rows.Add(drEmployment);

drEmployment = dtEmplStatus.NewRow();
drEmployment["EmplStatus"] = "Contractor";

C# 3.0 Practical Learning II 268


dtEmplStatus.Rows.Add(drEmployment);

drEmployment = dtEmplStatus.NewRow();
drEmployment["EmplStatus"] = "Intern";
dtEmplStatus.Rows.Add(drEmployment);

dsEmployment.Tables.Add(dtEmplStatus);
dsEmployment.Tables.Add(dtEmployees);

Console.WriteLine("================+===============+============
===");
Console.WriteLine("First Name\t|Last Name\t|
Department");
Console.WriteLine("----------------
+---------------+---------------");
foreach(DataRow row in
dsEmployment.Tables["Employees"].Rows)
Console.WriteLine("{0}\t\t|{1}\t\t|{2}",
row["FirstName"],
row["LastName"],
row["Department"]);

Console.WriteLine("================+===============+============
===\n");

Console.WriteLine("=================");
Console.WriteLine("Employment Status");
Console.WriteLine("-----------------");
foreach(DataRow row in
dsEmployment.Tables["EmploymentStatus"].Rows)
Console.WriteLine("{0}",
row["EmplStatus"]);
Console.WriteLine("=================");
Console.WriteLine();
}
}

This would produce:


================+===============+===============
First Name |Last Name |Department
----------------+---------------+---------------
Peter |Larsen |Accounting
Paul |Banack |IT/IM
Helene |Casson |Accounting
Anselme |Thoma |Public Relations
Bertha |Um |Corporate
================+===============+===============

=================
Employment Status
-----------------
Full Time

C# 3.0 Practical Learning II 269


Part Time
Contractor
Intern
=================

Creating a Relationship

As it should appear obvious, a relationship makes more sense in the presence


of at least two tables, although a table can (also) have some type of
relationship with itself. By the rules and suggestions of relational databases, for
a table to participate in a relationship, the table should provide at least one
column that would be used to uniquely represent or identify each record. Such
a column is usually called an index. Although it can be positioned anywhere in
the table, it is usually the first or most-left column. Also traditionally, the name
of this column ends with No, such as RecordNo, or an ID suffix, such as
RecordID.

In our first table, to uniquely identify each record, we can create a column
called EmployeeID and add an incremental number to each record. In the same
way, a column used to identify each department in the second table of our
example can be called EmploStatusID. The tables would then be created as
follows:
using System;
using System.Xml;
using System.Data;

class Exercise
{
static void Main()
{
DataSet dsEmployment = new
DataSet("Employment");
DataTable dtEmployees = new
DataTable("Employees");

DataColumn[] dcEmployees = new DataColumn[4];

dcEmployees[0] = new DataColumn("EmployeeID",

System.Type.GetType("System.Int32"));
dtEmployees.Columns.Add(dcEmployees[0]);
dcEmployees[1] = new DataColumn("FirstName",

System.Type.GetType("System.String"));
dtEmployees.Columns.Add(dcEmployees[1]);
dcEmployees[2] = new DataColumn("LastName",

System.Type.GetType("System.String"));
dtEmployees.Columns.Add(dcEmployees[2]);
dcEmployees[3] = new DataColumn("Department",

System.Type.GetType("System.String"));

C# 3.0 Practical Learning II 270


dtEmployees.Columns.Add(dcEmployees[3]);

DataRow drEmplRecord = dtEmployees.NewRow();


drEmplRecord["EmployeeID"] = "1";
drEmplRecord["FirstName"] = "Peter";
drEmplRecord["LastName"] = "Larsen";
drEmplRecord["Department"] = "Accounting";
dtEmployees.Rows.Add(drEmplRecord);

drEmplRecord = dtEmployees.NewRow();
drEmplRecord["EmployeeID"] = "2";
drEmplRecord["FirstName"] = "Paulin";
drEmplRecord["LastName"] = "Banack";
drEmplRecord["Department"] = "IT/IM";
dtEmployees.Rows.Add(drEmplRecord);

drEmplRecord = dtEmployees.NewRow();
drEmplRecord["EmployeeID"] = "3";
drEmplRecord["FirstName"] = "Helene";
drEmplRecord["LastName"] = "Casson";
drEmplRecord["Department"] = "Accounting";
dtEmployees.Rows.Add(drEmplRecord);

drEmplRecord = dtEmployees.NewRow();
drEmplRecord["EmployeeID"] = "4";
drEmplRecord["FirstName"] = "Anselme";
drEmplRecord["LastName"] = "Thomas";
drEmplRecord["Department"] = "Public Relations";
dtEmployees.Rows.Add(drEmplRecord);

drEmplRecord = dtEmployees.NewRow();
drEmplRecord["EmployeeID"] = "5";
drEmplRecord["FirstName"] = "Bertha";
drEmplRecord["LastName"] = "Colson";
drEmplRecord["Department"] = "Corporate";
dtEmployees.Rows.Add(drEmplRecord);

DataTable dtEmplStatus = new


DataTable("EmploymentStatus");

DataColumn[] dcEmployment = new DataColumn[2];

dcEmployment[0] = new DataColumn("EmplStatusID",

System.Type.GetType("System.Int32"));
dtEmplStatus.Columns.Add(dcEmployment[0]);
dcEmployment[1] = new DataColumn("EmplStatus",

System.Type.GetType("System.String"));
dtEmplStatus.Columns.Add(dcEmployment[1]);

DataRow drEmployment = dtEmplStatus.NewRow();


drEmployment["EmplStatusID"] = "1";
drEmployment["EmplStatus"] = "Full Time";
dtEmplStatus.Rows.Add(drEmployment);

C# 3.0 Practical Learning II 271


drEmployment = dtEmplStatus.NewRow();
drEmployment["EmplStatusID"] = "2";
drEmployment["EmplStatus"] = "Part Time";
dtEmplStatus.Rows.Add(drEmployment);

drEmployment = dtEmplStatus.NewRow();
drEmployment["EmplStatusID"] = "3";
drEmployment["EmplStatus"] = "Contractor";
dtEmplStatus.Rows.Add(drEmployment);

drEmployment = dtEmplStatus.NewRow();
drEmployment["EmplStatusID"] = "4";
drEmployment["EmplStatus"] = "Intern";
dtEmplStatus.Rows.Add(drEmployment);

dsEmployment.Tables.Add(dtEmplStatus);
dsEmployment.Tables.Add(dtEmployees);

Console.WriteLine("===+=============+===============+===========
======");
Console.WriteLine("ID | First Name\t | Last Name\t
| Department");
Console.WriteLine("---+-------------+---------------
+-----------------");
foreach(DataRow row in
dsEmployment.Tables["Employees"].Rows)
Console.WriteLine(" {0} | {1}\t | {2}\t |
{3}",
row["EmployeeID"],
row["FirstName"],
row["LastName"],
row["Department"]);
Console.WriteLine("===+=============+===============+===========
======\n");

Console.WriteLine("===+===================");
Console.WriteLine("ID | Employment Status");
Console.WriteLine("---+-------------------");
foreach(DataRow row in
dsEmployment.Tables["EmploymentStatus"].Rows)
Console.WriteLine(" {0} | {1}",
row["EmplStatusID"],
row["EmplStatus"]);
Console.WriteLine("===+===================");
Console.WriteLine();
}
}

This would produce:


===+=============+===============+=================
ID | First Name | Last Name | Department
---+-------------+---------------+-----------------
1 | Peter | Larsen | Accounting
2 | Paulin | Banack | IT/IM

C# 3.0 Practical Learning II 272


3 | Helene | Casson | Accounting
4 | Anselme | Thomas | Public Relations
5 | Bertha | Colson | Corporate
===+=============+===============+=================

===+===================
ID | Employment Status
---+-------------------
1 | Full Time
2 | Part Time
3 | Contractor
4 | Intern
===+===================

As mentioned already, this type of field is used to uniquely identify each record
of a table. Therefore, it is based on this field that a table can be related to
another. To actually create the relationship, in our example, to associate each
employee to a department, the table that holds the list of employees must have
a field that represents the corresponding department from the Departments
table and you must create such a new column. The most important rule you
must observe is that this new field must have the same data type as the
column that uniquely identifies each department in the other table. This field in
the Departments table is referred to as the Primary Key. The new column
created in the Employees table is referred to as the Foreign Key because this
column acts only as an "ambassador". In the strict sense, it doesn't belong to
the table in which it is created and in fact, its values should/must not be
changed by its hosting table.

After creating the foreign key column, the relationship is not automatically
applied between both tables, since neither the compiler nor the database
engine (if you were working on a database) is aware of the role of this new
field. To create a relationship between two DataTable objects, the Microsoft
.NET Framework provides the DataRelation class. As this is a small class, its
main role is to join two tables.

In order to create a relationship, you can declare a variable of type


DataRelation and use one of its 5 constructors to initialize the relationship.
The first constructor has the following syntax:

DataRelation(string relationName, DataColumn parentColumn,


DataColumn childColumn);

The first argument allows you to specify a name for the relationship.

The second argument must identify the primary key column of the table that
would supply the values. In our example, this would be the primary key of the
Departments table.

C# 3.0 Practical Learning II 273


The third argument is the column used as the foreign key in the table that
would receive the values of the other table. In our example, this would be the
foreign key of the Employees table.

This indicates that you should first define and identify the columns that would
be used in the relationship. Based on this description, the relationship can be
created as follows:

using System;
using System.Xml;
using System.Data;

class Exercise
{
static void Main()
{
DataSet dsEmployment = new
DataSet("Employment");
DataTable dtEmployees = new
DataTable("Employees");

DataColumn[] dcEmployees = new DataColumn[5];

dcEmployees[0] = new DataColumn("EmployeeID",

System.Type.GetType("System.Int32"));
dtEmployees.Columns.Add(dcEmployees[0]);
dcEmployees[1] = new DataColumn("FirstName",

System.Type.GetType("System.String"));
dtEmployees.Columns.Add(dcEmployees[1]);
dcEmployees[2] = new DataColumn("LastName",

System.Type.GetType("System.String"));
dtEmployees.Columns.Add(dcEmployees[2]);
dcEmployees[3] = new DataColumn("Department",

System.Type.GetType("System.String"));
dtEmployees.Columns.Add(dcEmployees[3]);
dcEmployees[4] = new DataColumn("EmplStatusID",

System.Type.GetType("System.Int32"));
dtEmployees.Columns.Add(dcEmployees[4]);

DataRow drEmplRecord = dtEmployees.NewRow();


drEmplRecord["EmployeeID"] = "1";
drEmplRecord["FirstName"] = "Peter";
drEmplRecord["LastName"] = "Larsen";
drEmplRecord["Department"] = "Accounting";
drEmplRecord["EmplStatusID"] = "1";
dtEmployees.Rows.Add(drEmplRecord);

C# 3.0 Practical Learning II 274


drEmplRecord = dtEmployees.NewRow();
drEmplRecord["EmployeeID"] = "2";
drEmplRecord["FirstName"] = "Paulin";
drEmplRecord["LastName"] = "Banack";
drEmplRecord["Department"] = "IT/IM";
drEmplRecord["EmplStatusID"] = "3";
dtEmployees.Rows.Add(drEmplRecord);

drEmplRecord = dtEmployees.NewRow();
drEmplRecord["EmployeeID"] = "3";
drEmplRecord["FirstName"] = "Helene";
drEmplRecord["LastName"] = "Casson";
drEmplRecord["Department"] = "Accounting";
drEmplRecord["EmplStatusID"] = "2";
dtEmployees.Rows.Add(drEmplRecord);

drEmplRecord = dtEmployees.NewRow();
drEmplRecord["EmployeeID"] = "4";
drEmplRecord["FirstName"] = "Anselme";
drEmplRecord["LastName"] = "Thomas";
drEmplRecord["Department"] = "Public Rel";
drEmplRecord["EmplStatusID"] = "1";
dtEmployees.Rows.Add(drEmplRecord);

drEmplRecord = dtEmployees.NewRow();
drEmplRecord["EmployeeID"] = "5";
drEmplRecord["FirstName"] = "Bertha";
drEmplRecord["LastName"] = "Colson";
drEmplRecord["Department"] = "Corporate";
drEmplRecord["EmplStatusID"] = "4";
dtEmployees.Rows.Add(drEmplRecord);

drEmplRecord = dtEmployees.NewRow();
drEmplRecord["EmployeeID"] = "6";
drEmplRecord["FirstName"] = "Renée";
drEmplRecord["LastName"] = "Bright";
drEmplRecord["Department"] = "IT/IM";
drEmplRecord["EmplStatusID"] = "3";
dtEmployees.Rows.Add(drEmplRecord);

drEmplRecord = dtEmployees.NewRow();
drEmplRecord["EmployeeID"] = "7";
drEmplRecord["FirstName"] = "Jeanne";
drEmplRecord["LastName"] = "Tristan";
drEmplRecord["Department"] = "Corporate";
drEmplRecord["EmplStatusID"] = "1";
dtEmployees.Rows.Add(drEmplRecord);

drEmplRecord = dtEmployees.NewRow();
drEmplRecord["EmployeeID"] = "8";
drEmplRecord["FirstName"] = "Sandrine";
drEmplRecord["LastName"] = "Holland";
drEmplRecord["Department"] = "Public Rel";
drEmplRecord["EmplStatusID"] = "4";
dtEmployees.Rows.Add(drEmplRecord);

C# 3.0 Practical Learning II 275


DataTable dtEmplStatus = new
DataTable("EmploymentStatus");

DataColumn[] dcEmployment = new DataColumn[2];

dcEmployment[0] = new DataColumn("EmplStatusID",

System.Type.GetType("System.Int32"));
dtEmplStatus.Columns.Add(dcEmployment[0]);
dcEmployment[1] = new DataColumn("EmplStatus",

System.Type.GetType("System.String"));
dtEmplStatus.Columns.Add(dcEmployment[1]);

DataRow drEmployment = dtEmplStatus.NewRow();


drEmployment["EmplStatusID"] = "1";
drEmployment["EmplStatus"] = "Full Time";
dtEmplStatus.Rows.Add(drEmployment);

drEmployment = dtEmplStatus.NewRow();
drEmployment["EmplStatusID"] = "2";
drEmployment["EmplStatus"] = "Part Time";
dtEmplStatus.Rows.Add(drEmployment);

drEmployment = dtEmplStatus.NewRow();
drEmployment["EmplStatusID"] = "3";
drEmployment["EmplStatus"] = "Contractor";
dtEmplStatus.Rows.Add(drEmployment);

drEmployment = dtEmplStatus.NewRow();
drEmployment["EmplStatusID"] = "4";
drEmployment["EmplStatus"] = "Intern";
dtEmplStatus.Rows.Add(drEmployment);

dsEmployment.Tables.Add(dtEmplStatus);
dsEmployment.Tables.Add(dtEmployees);

DataColumn colParent =

dsEmployment.Tables["EmploymentStatus"].Columns["EmplStatusID"];
DataColumn colChild =

dsEmployment.Tables["Employees"].Columns["EmplStatusID"];
DataRelation drEmployeeStatus =
new DataRelation("EmployeeStatus",
colParent, colChild);

dsEmployment.Relations.Add(drEmployeeStatus);

Console.WriteLine("===+===================");
Console.WriteLine("ID | Employment Status");
Console.WriteLine("---+-------------------");
foreach(DataRow row in
dsEmployment.Tables["EmploymentStatus"].Rows)

C# 3.0 Practical Learning II 276


Console.WriteLine(" {0} | {1}",
row["EmplStatusID"], row["EmplStatus"]);

Console.WriteLine("===+=============+===============+===========
====+=============");
Console.WriteLine("ID | First Name\t | Last Name\t
| Department\t | Empl Status");
Console.WriteLine("---+-------------+---------------
+---------------+-------------");
foreach(DataRow row in
dsEmployment.Tables["Employees"].Rows)
{
int iRow =
int.Parse(row["EmplStatusID"].ToString());
DataRow curRecord =
dsEmployment.Tables["EmploymentStatus"].Rows[iRow-1];

Console.WriteLine(" {0} | {1}\t | {2}\t |


{3}\t | {4}",
row["EmployeeID"], row["FirstName"],
row["LastName"], row["Department"],
curRecord["EmplStatus"]);
}
Console.WriteLine("===+=============+===============+===========
====+=============\n");
}
}

This would produce:


===+===================
ID | Employment Status
---+-------------------
1 | Full Time
2 | Part Time
3 | Contractor
4 | Intern
===+=============+===============+===============+=============
ID | First Name | Last Name | Department | Empl Status
---+-------------+---------------+---------------+-------------
1 | Peter | Larsen | Accounting | Full Time
2 | Paulin | Banack | IT/IM | Contractor
3 | Helene | Casson | Accounting | Part Time
4 | Anselme | Thomas | Public Rel | Full Time
5 | Bertha | Colson | Corporate | Intern
6 | Renée | Bright | IT/IM | Contractor
7 | Jeanne | Tristan | Corporate | Full Time
8 | Sandrine | Holland | Public Rel | Intern
===+=============+===============+===============+=============

Press any key to continue . . .

C# 3.0 Practical Learning II 277


C# 3.0 Practical Learning II 278
Introduction to ADO
 

ADO Fundamentals
 

Introduction to Databases

In various lessons, we have learned how to create lists and collections. A


database is a list or a group of lists of objects organized to make the list(s)
and its (their) values easy to create and manage. In the computer world, this
suggests, rightly, that the list(s) and its(their) values is(are) stored in a
machine. Based on this importance, almost every company keeps some type
of database, whether it includes its employees, its customers, or the products
it sells.

A database is a project that holds one or more lists of items. There can be
other issues involved, such as how the data would be made available to the
users, what computer(s) would access the data, what types of users would
access the database. The database could reside in one computer and used by
one person. A database can also be stored in one computer but accessed by
different computers on a network. Another database can be created and
stored in a server to be accessed through the Internet. These and other
related scenarios should be dealt with to create and distribute the database.

  

Microsoft JET

To make it possible to create computer databases, Microsoft developed


various libraries and programming environments. Microsoft JET is a library
used to create and manage Microsoft Access types of databases using a
language or a programming environment of your choice. This means that the
library can be used from either Microsoft Access, another Microsoft
development studio, or an environment from another company. To make
this possible, you must first obtain the library. In most cases, you should have
this library already installed in your computer. If not, it is freely available by
downloading from the Microsoft web site. Once there, simply do a search on
"Microsoft JET". After downloading it, install it. 

C# 3.0 Practical Learning II 279


Microsoft ActiveX Data Objects or ADO, is a library used to manage
databases. To make it possible, it uses the driver that is part of Microsoft JET.

Microsoft ActiveX Data Object Extensions for Data Definition Language and
Security abbreviated ADOX, is an addition to ADO. It can be used to create
and manage a database, providing some of the same operations as ADO but
also some operations not possible in ADO.

Any computer language or programming environment that wants to use


Microsoft JET provides its own means of accessing the library. In fact, it is not
unusual to manually write code that takes advantage of Microsoft JET. This is
usually how some programmers would create and manage a web database
(through Active Server Pages (ASP)). Still, in most cases, and depending on
the language you decide to use to create and manage your database, you
would need either only an interpreter (which is the case if you plan to use
VBScript, JavaScript, or another interpreted language) or a compiler.

Referencing a Library in a .NET Framework

Based on its flexibility, you can use the .NET Framework to create and
manage Microsoft JET databases. The .NET Framework is a group of many
libraries under one name. When creating a project, you choose what libraries
you would use, based on your goal, to perform the necessary tasks. If you
are using a visual environment, you can "visually" reference the library. Based
on this, to create an application that uses the ADO library, you can add its
reference in the Solution Explorer.

Microsoft ADO Ext.


 

Introduction

To get a database, you can either use one that exists already or you can
create your own. ADO by itself doesn't provide the means to create a
database. To create one, you can use the Microsoft ActiveX Data Objects
Extensions for Data Definition Language and Security, abbreviated ADOX.
Before using ADOX, you must reference it in your C# project. To do this, on
the main menu of Microsoft Visual C#, you can click Project -> Add
Reference... As an alternative, in the Solution Explorer, you can right-click the
name of the project and click Add References...

In the COM tab of the Add Reference dialog box, locate the Microsoft ADO
Ext. 2.8 for DDL and Security:

C# 3.0 Practical Learning II 280


After referencing the library, you can use its classes. The classes of the ADOX
library are stored in a namespace named ADOX.

The Catalog Class

To create and manage various objects of a database, the ADOX namespace


provides an interface named Catalog and its derived class is named
CatalogClass. To use this class, you can first declare its variable. Here is an
example:

using System;

public class Program


{
static int Main()
{
ADOX.CatalogClass catDatabase;

return 0;
}
}

After declaring the class, you can initialize it using the new operator:
using System;

public class Program


{
static int Main()

C# 3.0 Practical Learning II 281


{
ADOX.CatalogClass catDatabase;

catDatabase = new ADOX.CatalogClass();

return 0;
}
}

Database Creation
 

The Catalog Class

To support database creation, the ADO library provides an interface named


Catalog. In the .NET Framework, this interface is type-defined as the
CatalogClass class.

To support the creation of a database, the CatalogClass class is equipped


with a method named Create. Its syntax is:
public object Create(string ConnectionString)

The Create() method takes one argument referred to as the connection


string. Here is an example of calling it:
using System;

public class Program


{
static int Main()
{
ADOX.CatalogClass catDatabase;

catDatabase = new ADOX.CatalogClass();


catDatabase.Create("");

return 0;
}
}

This string is made of sections separated by semi-colons. The formula used


by these sections is:
Key1=Value1;Key2=Value2;Key_n=Value_n;

The Provider

The first part of the connection string is called the provider. It is software that
handles the database. To specify it, assign the desired name to the provider
key. Here is an example:

C# 3.0 Practical Learning II 282


using System;

public class Program


{
static int Main()
{
ADOX.CatalogClass catDatabase;

catDatabase = new ADOX.CatalogClass();


catDatabase.Create("Provider=");

return 0;
}
}

There are various providers in the database industry. One of them is Microsoft
SQL Server and it is represented by SQLOLEDB. If you want to create a
Microsoft SQL Server database, specify this provider. Here is an example:
using System;

public class Program


{
static int Main()
{
ADOX.CatalogClass catDatabase;

catDatabase = new ADOX.CatalogClass();


catDatabase.Create("Provider=SQLOLEDB;");
return 0;
}
}

When creating this type of database, there are some other pieces of
information you must provide in the connection string.

Another provider is the Microsoft JET database engine represented as


Microsoft.JET.OLEDB.4.0. To create a database for it,  specify its provider
accordingly. Here is an example:
using System;

public class Program


{
static int Main()
{
ADOX.CatalogClass catDatabase;

catDatabase = new ADOX.CatalogClass();


catDatabase.Create("Provider=Microsoft.Jet.OLEDB.4.0;");
return 0;
}
}

The Data Source of a Connection String

C# 3.0 Practical Learning II 283


A database is created as a computer file and it has a path, that is, where the
database file is located. The path to a file is also known as its location. The
path to a database, including its name, is also called the data source. In some
of your database operations, you will be asked to provide a data source for
your database. In this case, provide the complete path followed by the name
of the database.

If you are creating a database, the second part of the connection string can
be used to specify the path and the name of the database. This section must
start with the Data Source key and assigned the path that consists of the
drive and the folder(s). After the last folder, the name of the database must
have the .mdb extension. For example, to create a database called Exercise1
that would reside in a folder called Programs on the C: drive, you can specify
the connection string as follows:
using System;

public static class Program


{
static int Main()
{
ADOX.CatalogClass catADO = new ADOX.CatalogClass();

catADO.Create("Provider=Microsoft.Jet.OLEDB.4.0;" +
"Data
Source='C:\\Programs\\Exercise1.mdb'");
Console.WriteLine("A new Microsoft JET database named "
+
"Exercise1.mdb has been created");
return 0;
}
}

This would produce:


A new Microsoft JET database named Exercise1.mdb has been
created
Press any key to continue . . .

Instead of directly passing a string to the Create() method, you can first
declare a string variable, initialize it with the necessary provider/data
source, and then pass that string variable to the Create() method. Here is
an example:
using System;

public class Program


{
static int Main()
{
ADOX.CatalogClass catDatabase;
string strDatabase = "Provider=Microsoft.Jet.OLEDB.4.0;"
+

C# 3.0 Practical Learning II 284


"Data
Source='C:\\Programs\\Exercise1.mdb'";

catDatabase = new ADOX.CatalogClass();


catDatabase.Create(strDatabase);
Console.WriteLine("A new Microsoft JET database named "
+
"Exercise1.mdb has been created\n");
return 0;
}
}

The ODBC Data Source 

If you plan to access your database from another programming environment,


then you should create an ODBC data source. To do this, in the Control Panel
or the Administrative Tools, double-click Data Source (ODBC) to open the
ODBC Data Source Administrator:

To proceed, click the Add button. This would launch a wizard. In the first
page of the Create New Data Source wizard, click Microsoft Access Driver
(*.mdb):

C# 3.0 Practical Learning II 285


Click Finish. In the following screen, you would be asked to enter a name for
the data source. You can enter the name in one or more words. The name
would be used by the applications that need to access the database. This
means that you should pay attention to the name you give. In the Description
text box, you can enter a short sentence anyway you like. To specify the
database that would be used, click Select and select an mdb database. Here
is an example:

After selecting the necessary database, if you need to be authenticated in


order to use the database (if the database is protected), click the Advanced
button. By default, a database is meant to allow anybody to use it. In this
case, you can leave the Login Name and the Password empty. Otherwise,
type the necessary credentials:

C# 3.0 Practical Learning II 286


After using the Set Advanced Options dialog box, click OK (or Cancel to keep
it the way it previously was).

After entering the necessary information and selecting the desired database,
you can click OK twice.

Using the Microsoft ActiveX Data Objects (ADO)


 

Referencing ADO

C# 3.0 Practical Learning II 287


As mentioned earlier, Microsoft ActiveX Data Objects, or ADO, is a library
used to create databases. Before using this library, you must import it in your
application. To do this, you can right-click the References node in the Solution
Explorer for your project and click Add Reference... In the COM tab of the
Add Reference dialog box, select the latest Microsoft ActiveX Data Object
Library:

And click OK. This would add the ADO reference to your project.

The ADODB Namespace

The ADO library is represented in the .NET Framework by the ADODB


namespace. It contains various classes that you can access by qualifying
them through this namespace. As done with the other classes that belong to
a namespace, if you want, in the top section of the file where you would use
ADO, you can add the ADODB namespace. Here is an example:
using System;
using ADODB;

public class Program


{
static int Main()
{
return 0;
}
}

C# 3.0 Practical Learning II 288


The Connection to a Database
 

Introduction

To use or access a database, a user typically launches it and opens the


necessary object(s) from it. You too will need to access a database but with
code. To programmatically access a database using the ADO library, you must
first establish a connection. To support this, the ADODB namespace provides
an interface named Connection. In the .NET Framework, the Connection
interface is defined by a class named ConnectionClass.

To create a connection to a database, declare a variable of type Connection


or ADODB.ConnectionClass and initialize it using the new operator. This
would be done as follows:
using System;

public class Program


{
static int Main()
{
ADODB.Connection conDatabase = new ADODB.Connection();
return 0;
}
}

This can also be done as follows:


using System;
using ADODB;

public class Program


{
static int Main()
{
ConnectionClass conDatabase = new ConnectionClass();

return 0;
}
}

Opening a Connection

After declaring and initializing the Connection object, you can then open the
connection. To support this, the Connection interface (the
ConnectionClass class) is equipped with a method named Open. The syntax
of the Connection.Open method is:
public void _Connection.Open(string ConnectionString,
string UserID,

C# 3.0 Practical Learning II 289


string Password,
int Options

As you can see, this method takes four arguments and all of them are
required.

The Connection String

When establishing a connection to a database, you have two alternatives, you


can use the first argument to the Connection.Open() method or you can
separately create a connection string.

The connection string is text made of various sections separated by semi-


colons. Each section is made of a Key=Value expression. Based on this, a
connection string uses the following formula:
Key1=Value1;Key2=Value2;Key_n=Value_n;

One of the expressions you can specify in the connection string is the name
of the provider. To do this, type Provider= followed by the provider you are
using. For most databases we will create or use here, the provider will be
Microsoft.JET.OLEDB.4.0. This means that our connection string can start
with:
using System;
using ADODB;

public static class Program


{
static int Main()
{
ConnectionClass conDatabase = new ConnectionClass();

string strConnection=
"Provider=Microsoft.Jet.OLEDB.4.0;". . .

return 0;
}
}

You can also include the value of the provider in single-quotes to delimit it.

The second part of the connection string specifies the data source. To provide
this information, you can assign the path and name of the database to the
Data Source attribute. Here is an example:

using System;
using ADODB;

public static class Program


{
static int Main()
{

C# 3.0 Practical Learning II 290


ConnectionClass conDatabase = new ConnectionClass();

string strConnection =
"Provider=Microsoft.Jet.OLEDB.4.0;" +
"Data
Source='C:\\Programs\\Exercise1.mdb';";

return 0;
}
}

It is important to note that the content of the connection string differs from
one provider to another. If you were working on a Microsoft SQL Server
database, your connection string would be different from the above done for
a Microsoft JET database. For example, if you were working on an MSDE or a
Microsoft SQL Server database, the provider would be SQLOLEDB.

After creating the connection string, you can then pass it to the
Connection.Open() method as the first argument. Here is an example:

using System;
using ADODB;

public static class Program


{
static int Main()
{
ConnectionClass conDatabase = new ConnectionClass();

string strConnection =
"Provider=Microsoft.Jet.OLEDB.4.0;" +
"Data
Source='C:\\Programs\\Exercise1.mdb';";

conDatabase.Open(strConnection, );
return 0;
}
}

The Login Credentials

When creating your database, if you are working in a secure environment and
the database requires authentication, you may need to provide login
credentials, which include a username and a password. Normally, these
properties are mostly applied if you are working on a Microsoft SQL Server
database.

To specify the login credentials when accessing the database, you can pass
the second and the third arguments to the Open() method of the
Connection class. If you don't have this information, you can pass each
argument as an empty string. Here is an example:
using System;

C# 3.0 Practical Learning II 291


using ADODB;

public class Program


{
static int Main()
{
ConnectionClass conDatabase= new ConnectionClass();

string strConnection =
"Provider=Microsoft.Jet.OLEDB.4.0;" +
"Data
Source='C:\\Programs\\Exercise1.mdb';";

conDatabase.Open(strConnection, "", "", );


return 0;
}
}

The fourth argument of the Connection.Open() method specifies whether


the method should return after establishing the connection. If undecided, you
can pass this argument as 0:
using System;
using ADODB;

public class Program


{
static int Main()
{
ConnectionClass conDatabase = new ConnectionClass();

string strConnection =
"Provider=Microsoft.Jet.OLEDB.4.0;" +
"Data
Source='C:\\Programs\\Exercise1.mdb';";

conDatabase.Open(strConnection, "", "", 0);


return 0;
}
}

Executing a SQL Statement

After creating a connection to a database, you can specify what you want to
do on the database. One of the most common operations you can perform is
to submit a statement to it (the connection). This is also equivalent to
executing the statement.

To execute a statement, the Connection class is equipped with the


Execute() method. Its syntax is:

public Recordset _Connection.Execute(string CommandText,


out object RecordsAffected,
int Options);

C# 3.0 Practical Learning II 292


The first argument, CommandText, can be a type of statement we will study
in future lessons. The second argument, passed by reference, specifies the
number of records that were affected by the operation. The third argument
specifies how the provider should evaluate the command. If undecided, pass
this argument as 0.

Here is an example of calling the Connection.Execute() method:


using System;
using ADODB;

public class Program


{
static int Main()
{
object objAffected;
string strStatement = "Something";
ConnectionClass conDatabase = new ConnectionClass();

string strConnection =
"Provider=Microsoft.Jet.OLEDB.4.0;" +
"Data
Source='C:\\Programs\\Exercise1.mdb';";

conADO.Open(strConnection, "", "", 0);


conADO.Execute(strStatement, out objAffected, 0);

return 0;
}
}

When it is called, the Execute() method of the Connection class examines


and executes its (first) argument, in this case strStatement. If this method
succeeds, it returns a list of records.

Closing a Connection

When using a connection, it consumes resources that other applications may


need. Therefore, after using it, you should close it and free the resources it
was using so they can be made available to the other parts of the computer.
To close a connection, the Connection class is equipped with the Close()
method. This can be done as follows:
using System;
using ADODB;

public class Program


{
static int Main()
{
object objAffected;
string strStatement = "Something";
ConnectionClass conDatabase = new ConnectionClass();

C# 3.0 Practical Learning II 293


string strConnection =
"Provider=Microsoft.Jet.OLEDB.4.0;" +
"Data
Source='C:\\Programs\\Exercise1.mdb';";

conDatabase.Open(strConnection, "", "", 0);


conDatabase.Execute(strStatement, out objAffected, 0);

conADO.Close();
return 0;
}
}

Probably a better way would consist of using a try...finally block to close


the connection. Here is an example:
using System;
using ADODB;

public static class Program


{
static int Main()
{
object objAffected;
string strStatement = "Something";
ConnectionClass conDatabase = new ConnectionClass();

try
{
string strConnection =
"Provider=Microsoft.Jet.OLEDB.4.0;" +
"Data
Source='C:\\Programs\\Exercise1.mdb';";

conDatabase.Open(strConnection, "", "", 0);


conDatabase.Execute(strStatement, out objAffected,
0);
}
finally
{
conADO.Close();
}

return 0;
}
}

C# 3.0 Practical Learning II 294


The Records of a
Database
 

Table Creation
 

Introduction

When studying data sets, we defined a database as one or more lists. A list
in a database is called a table. The idea is that a table is an arrangement of
the categories of information stored in a list and a table makes it easy to
locate and manage the records of a list. To better explore lists, you should
know how a table organizes its value.

A table is made of one or more categories divided as columns. Consider the


following example of a list of teachers of a high school:

  

First Alternate
Last Name Main Subject
Name Subject

Pastore Albert Math Physics

Andong Gertrude Chemistry Static

Missiano Helena Physical Ed  

Jones Celestine Comp Sciences Math

Notice that the first names are grouped in a common category, so are the last
names and so on. This makes it easy to locate a category and possibly a
value.

Table Creation

C# 3.0 Practical Learning II 295


To create a table, you start an expression with CREATE TABLE followed by the
name of the table:
CREATE TABLE Name;

The CREATE and TABLE keywords must be used to create a table. The Name
factor specifies the name of the new table.

The Name of a Table

After the CREATE TABLE expression, you must enter a name for the table.
The name of a table can be very flexible. This flexibility can be overwhelming
and confusing. To avoid these, there are suggestions and conventions we will
apply when naming our tables:

 The name of a table will start with a letter. In most cases, the name will
start in uppercase

 Because we believe that a table represents a list of items, its name will
be in plural. Examples are Students, Employees, Products

 When a name is a combination of words, each part will start in


uppercase. Examples are Student Names or Sport Activities

 In most cases, we will avoid including space in a name; but if we do, the
name of a table will be included between [ and ]

Here is an example:
using System;
using ADODB;

public class Program


{
static int Main()
{
string strStatement = "CREATE TABLE Persons...";

return 0;
}
}

After formulating the expression that creates the table, you can pass it to the
Execute() method of a Connection variable. This would be done as follows:

using System;
using ADODB;

public class Program


{
static int Main()
{

C# 3.0 Practical Learning II 296


ConnectionClass conDatabase = new ConnectionClass();

try
{
object objAffected;
string strStatement = "CREATE TABLE Persons...";
string strConnection =
"Provider=Microsoft.Jet.OLEDB.4.0;" +
"Data
Source='C:\\Programs\\Exercise1.mdb';";

conDatabase.Open(strConnection, "", "", 0);


conDatabase.Execute(strStatement, out objAffected,
0);
}
finally
{
conDatabase.Close();
}
return 0;
}
}

Besides the CREATE TABLE expression followed by a name, there are other
issues related to creating a table. We will review more details in future
lessons.

Table Maintenance
 

The Tables Collection

The tables of an ADO database are stored in a collection represented in the


Connection class by the Tables property. To locate this collection, you can
access the Tables property of the Catalog class of the ADOX namespace.

Deleting a Table

To remove a table from a database, create a DROP TABLE expression followed


by the name of the table. The formula to use is:
DROP TABLE TableName;

Replace the TableName factor of our formula with the name of the table you
want to delete. Here is an example:
using System;
using ADODB;

public class Program


{

C# 3.0 Practical Learning II 297


static int Main()
{
ConnectionClass conDatabase = new ConnectionClass();

try
{
object objAffected;
string strStatement = "DROP TABLE Persons";
string strConnection =
"Provider=Microsoft.Jet.OLEDB.4.0;" +
"Data
Source='C:\\Programs\\Exercise1.mdb';";

conDatabase.Open(strConnection, "", "", 0);


conDatabase.Execute(strStatement, out objAffected,
0);
}
finally
{
conDatabase.Close();
}
return 0;
}
}

Columns Fundamentals
 

Introduction

We saw that a table was used to organize the values of a list by using
categories of information. Here is an example:

First Years of
Last Name Main Class
Name Experience

Pastore Albert Math 4

Andong Gertrude Chemistry 8

Missiano Helena Physical Ed 5

Comp
Jones Celestine 10
Sciences

With this type of arrangement, each column holds a particular category of


information. A table must have at least one column. This means that, to

C# 3.0 Practical Learning II 298


create a table using the CREATE TABLE TableName formula, you must specify
a (at least one) column.

Column Creation

To create the columns of a table, on the right side of the name, type an
opening and a closing parentheses. In the parentheses of the CREATE TABLE
TableName() expression, the formula of creating a column is:
ColumnName DataType Options

Notice that there is only space that separates the sections of the formula.
This formula is for creating one column. If you want the table to have more
than one column, follow this formula as many times as possible but separate
the sections with colons. This would be done as follows:
CREATE TABLE TableName(Column1 DataType1 Options1,
Column2 DataType2 Options2,
Column_n DataType_n Options_n)

In the next sections, we will review the factors of this formula. To create a
table in ADO, you can pass the whole statement to the Execute() method of
the Connection class.

Characteristics of a Column
 

Introduction

Like a table of a database, a column must have a name. As mentioned for a


table, the name of a column is very flexible. Because of this, we will adopt the
same types of naming conventions we reviewed for tables:

 The name of a column will start with a letter. In most cases, the name
will start in uppercase

 When a name is a combination of words, each part will start in


uppercase. Examples are First Name or Date Hired

 In most cases, we will avoid including space in a name but if we do, the
name of the column will be included between [ and ]

When creating the table, set the name of the column in the ColumnName
placeholder of our formula. Here is an example:
CREATE TABLE Students(FullName, DataType Options)

Notice that the name of the column is not included in quotes.

The Types of Columns

C# 3.0 Practical Learning II 299


To exercise a good level of control over the values that can be entered or
stored in a database, you can configure each column to allow some types of
value and/or to exclude some other types. This is done by specifying an
appropriate type of data for the column. To specify the data type of a column,
pass the name of the data type as the second factor of the column.

Text-Based Columns: If the fields under a column would be used to hold


any type of value, including regular text, such a column is treated as string-
based. There are various data types you can apply to such a column. You can
specify the data type as Char, Text, String or Varchar. Here are examples
of three columns created with these types:
using System;
using ADODB;

public class Program


{
static int Main()
{
ConnectionClass conDatabase = new ConnectionClass();

try
{
object objAffected;
string strStatement = "CREATE TABLE
Customers(FirstName char, " +

"MiddleName String, " +

"LastName varchar);";
string strConnection =
"Provider=Microsoft.Jet.OLEDB.4.0;" +
"Data
Source='C:\\Programs\\Exercise1.mdb';";

conDatabase.Open(strConnection, "", "", 0);


conDatabase.Execute(strStatement, out objAffected,
0);
}
finally
{
conDatabase.Close();
}
return 0;
}
}

Each one of the char, string, or varchar data types would produce the
same effect. A column with the string, the char, or the varchar data type
allows any type of value made of any character up to 255 symbols. If you
want the column to hold longer text, specify its data type as Memo, NOTE, or
LONGTEXT. Such a column can hold any type of text, any combination of
characters, and symbols, up to 64000 characters. Here are examples:

C# 3.0 Practical Learning II 300


using System;
using ADODB;

public class Program


{
static int Main()
{
ConnectionClass conDatabase = new ConnectionClass();

try
{
object objAffected;
string strStatement = "CREATE TABLE
Employees(FullName String, " +

"JobDescription Text, " +


"Comments
Memo, " +

"ShortTimeGoals Note, " +

"LongTimeGoals LongText);";
string strConnection =
"Provider=Microsoft.Jet.OLEDB.4.0;" +
"Data
Source='C:\\Programs\\Exercise1.mdb';";

conDatabase.Open(strConnection, "", "", 0);


conDatabase.Execute(strStatement, out objAffected,
0);
}
finally
{
conDatabase.Close();
}
return 0;
}
}

Boolean Columns: If you want to create a column to hold only values as


being true or being false, specify its data type as YESNO, BIT, or LOGICAL.
Here are examples:
using System;
using ADODB;

public class Program


{
static int Main()
{
ConnectionClass conDatabase = new ConnectionClass();

try
{
object objAffected;
string strStatement = "CREATE TABLE Contractors(" +

C# 3.0 Practical Learning II 301


"FullName String, "
+
"IsFullTime BIT, " +

"CanTeachVariousSubjects LOGICAL, " +


"IsMarried YESNO);";
string strConnection =
"Provider=Microsoft.Jet.OLEDB.4.0;" +
"Data
Source='C:\\Programs\\Exercise1.mdb';";

conDatabase.Open(strConnection, "", "", 0);


conDatabase.Execute(strStatement, out objAffected,
0);
}
finally
{
conDatabase.Close();
}
return 0;
}
}

Byte and Integer1: If you want a column to hold natural numbers, you
can specify its data type as Byte or Integer1. This is suited for a column
that will hold small numeric values not to exceed 255. Here are examples:
using System;
using ADODB;

public class Program


{
static int Main()
{
ConnectionClass conDatabase = new ConnectionClass();

try
{
object objAffected;
string strStatement = "CREATE TABLE
EmploymentStatus(" +
"StatusID Byte,
" +
"Category
Integer1);";
string strConnection =
"Provider=Microsoft.Jet.OLEDB.4.0;" +
"Data
Source='C:\\Programs\\Exercise1.mdb';";

conDatabase.Open(strConnection, "", "", 0);


conDatabase.Execute(strStatement, out objAffected,
0);
}
finally
{

C# 3.0 Practical Learning II 302


conDatabase.Close();
}
return 0;
}
}

Short and Integer2: If you want the column to hold larger numbers that
can exceed 255, specify its data type as SHORT or INTEGER2. 

Long: If the column will hold small to very large numbers, specify its data
type as INT, INTEGER, INTEGER4 or Long.

Floating-Point Value With Single Precision: If you want to create a


column that will hold regular decimal values without regards to precision on
its value, specify its data type as Single. 

Floating-Point Value With Double Precision: If the values of a


column will require a good level of precision, specify its data type as either
Double, or Numeric. Here is an example:

using System;
using ADODB;

public class Program


{
static int Main()
{
ConnectionClass conDatabase = new ConnectionClass();

try
{
object objAffected;
string strStatement = "CREATE TABLE Students(" +
"FullName varchar, "
+
"Height Single, " +
"Weight Numeric, " +
"GPA Double);";
string strConnection =
"Provider=Microsoft.Jet.OLEDB.4.0;" +
"Data
Source='C:\\Programs\\Exercise1.mdb';";

conDatabase.Open(strConnection, "", "", 0);


conDatabase.Execute(strStatement, out objAffected,
0);
}
finally
{
conDatabase.Close();
}
return 0;
}
}

C# 3.0 Practical Learning II 303


Money and Currency Columns: If you want the values of a column to hold
monetary values, specify its data type as either Money or Currency. Here is
an example:
using System;
using ADODB;

public class Program


{
static int Main()
{
ADODB.ConnectionClass conADO = new
ADODB.ConnectionClass();
string strCreate;
object obj = new object();

conADO.Open("Provider=Microsoft.Jet.OLEDB.4.0;" +
"Data Source='C:\\Programs\\Exercise1.mdb'",
"", "", 0);
strCreate = "CREATE TABLE Customers(" +
"FullName Text, " +
"WeeklyHours Double, " +
"HourlySalary Money, " +
"WeeklySalary Currency);";
conADO.Execute(strCreate, out obj, 0);
Console.WriteLine("A table named Customers has been added
to the database");
conADO.Close();

return 0;
}
}

Both Money and Currency have the same effect.

Date and Time: If you are creating a column whose values would consist of
date, time, or both date and time, specify its data type as DATE or DATETIME.
Here are examples:
using System;
using ADODB;

public class Program


{
static int Main()
{
ADODB.ConnectionClass conADO = new
ADODB.ConnectionClass();
string strCreate;
object obj = new object();

conADO.Open("Provider=Microsoft.Jet.OLEDB.4.0;" +
"Data
Source='C:\\Programs\\Exercise1.mdb'", "", "", 0);
strCreate = "CREATE TABLE Teachers(" +

C# 3.0 Practical Learning II 304


"FullName Text, " +
"DateHired Date, " +
"DateLastReviewed DateTime);";

conADO.Execute(strCreate, out obj, 0);


Console.WriteLine("A table named Teachers has been
added to the database");
conADO.Close();

return 0;
}
}

Both data types have the same effect in Microsoft Access.

Binary: The binary data type can let a column accept any type of data but it
is equipped to interpret the value. For example, it can be used to receive
hexadecimal numbers. To specify this when creating a column, set its data
type to either BINARY or VARBINARY.

Image: If you are creating a column that will hold external documents, such
as pictures, formatted (from Microsoft Word for example), or spreadsheet,
etc, specify its data type to one of the following: IMAGE, OLEOBJECT,
LONGBINARY, or GENERAL.

Column Maintenance
 

Introduction

Column maintenance consists of adding a new column or deleting an existing


column. Because the columns belong to a table, their maintenance is related
to it. To perform this maintenance, you start with the ALTER TABLE
expression followed by the name of the table.

Adding a New Column

After a table with one or more columns has been created, you can add a new
column to it. To add a new column, after the ALTER TABLE statement and
the name of the table, include an ADD COLUMN expression using the following
formula:
ALTER TABLE TableName
ADD COLUMN ColumnName DataType

The ColumnName factor must be a valid name for the new column and you
must follow the rules for naming columns. The data type must be one of
those we reviewed. Here is an example that adds a new string-based column
named CellPhone to a table named Employees:

C# 3.0 Practical Learning II 305


using System;
using ADODB;

public static class Program


{
static int Main()
{
ADODB.Connection conADO = new ADODB.Connection();
object obj = new object();
string strStatement;

conADO.Open("Provider=Microsoft.Jet.OLEDB.4.0;" +
"Data
Source='C:\\Programs\\Exercise1.mdb'", "", "", 0);
strStatement = "ALTER TABLE Employees ADD COLUMN
CellPhone string;";
conADO.Execute(strStatement, out obj, 0);

Console.WriteLine("A new column named CellPhone has


been added " +
"to the Employees table.");

conADO.Close();

return 0;
}
}

It is important to understand that the ADD COLUMN expression creates a new


column at the end of the existing column(s). It cannot be used to insert a
column in a table.

Deleting a Column

To delete a column, start with the ALTER TABLE expression followed by the
name of the table. After the ALTER TABLE TableName expression, follow it
with a DROP COLUMN expression using this formula:
ALTER TABLE TableName DROP COLUMN ColumnName;

Replace the ColumnName factor of our formula with the name of the
undesired column. Here is an example:

using System;
using ADODB;

public static class Program


{
static int Main()
{
ADODB.Connection conADO = new ADODB.Connection();
object obj = new object();

C# 3.0 Practical Learning II 306


string strStatement;

conADO.Open("Provider=Microsoft.Jet.OLEDB.4.0;" +
"Data
Source='C:\\Programs\\Exercise1.mdb'", "", "", 0);
strStatement = "ALTER TABLE Employees DROP COLUMN
Comments;";
conADO.Execute(strStatement, out obj, 0);

Console.WriteLine("The Comments column has been


deleted from the Employees table.");

conADO.Close();

return 0;
}
}

Data Entry Fundamentals


 

Introduction

So far, we have learned how to create a database and how to create a table.
Here are the database and the table we will use:
using System;
using ADODB;

public class Program


{
static int Main()
{
string strSQL;
object obj = new object();
ADOX.Catalog catPeople = new ADOX.Catalog();
ADODB.Connection conPeople = new ADODB.Connection();

try
{
catPeople.Create("Provider=Microsoft.Jet.OLEDB.4.0;"
+
"Data
Source='C:\\Programs\\People.mdb';");
Console.WriteLine("A new Microsoft JET database
named " +
"People.mdb has been created");

conPeople.Open("Provider=Microsoft.Jet.OLEDB.4.0;" +
"Data
Source='C:\\Programs\\People.mdb'",
"", "", 0);

C# 3.0 Practical Learning II 307


strSQL = "CREATE TABLE Persons(FirstName Text(20), "
+
"LastName Text(20), "
+
"Gender Text(20));";
conPeople.Execute(strSQL, out obj, 0);
Console.WriteLine("A table named Persons has been "
+
"created in the People.mdb
database");
}
finally
{
conPeople.Close();
}

return 0;
}
}

This creates a Microsoft JET database named People, followed by a table


named Persons equipped with three columns.

After creating a table and its column(s), you can populate the database with
data. Data entry consists of filling a table with the necessary values. A series
of values that corresponds to same levels of columns is called a row or a
record.

New Record Creation

Before performing data entry on a table, you must know how the table is
structured, the sequence of its columns, the type of data that each column is
made of. To enter data in a table, you start with the INSERT combined with
the VALUES keywords. The statement uses the following syntax:
INSERT TableName VALUES(Column1, Column2, Column_n)

Alternatively, or to be more precise, you can specify that you are entering
data in the table using the INTO keyword between the INSERT keyword and
the TableName factor. This is done with the following syntax:
INSERT INTO TableName VALUES(Column1, Column2, Column_n)

The TableName factor must be a valid name of an existing table in the


currently selected database. If the name is wrong, the SQL interpreter would
simply consider that the table you are referring to doesn't exist.
Consequently, you would receive an error.

The VALUES keyword indicates that you are ready to list the values of the
columns. The values of the columns must be included in parentheses. Specify
the value of each column in the parentheses that follow the VALUES keyword:

C# 3.0 Practical Learning II 308


Boolean Values: If the column is Boolean-based, you must specify its value
as 0 or 1.

Numeric Values: If the column is a numeric type and if the number is an


integer, you should provide a valid natural number without the decimal
separator. If the column is for a decimal number, you can type the value with
its character separator (the period for US English).

Character and String Values: If the data type of a column is a string


type, you should include its value between double-quotes. For example, a
shelf number can be specified as 'HHR-604' and a middle initial can be given
as 'D'.

Date and Time Values: If the column was created for a date or a time data
type, you should/must use an appropriate formula with the year represented
by 2 or 4 digits. You should also include the date in single-quotes. If you want
to specify the year with 2 digits, use the formula:
'yy-mm-dd'

Or
'yy/mm/dd'

You can use the dash symbol "-" or the forward slash "/" as the date
separator. An alternative to representing a year is with 4 digits. In this case,
you would use the formulas:
'yyyy-mm-dd'

Or
'yyyy/mm/dd'

The year with 4 digits is more precise as it properly expresses a complete


year.

A month from January to September can be represented as 1, 2, 3, 4, 5, 6, 7,


8, or 9. Day numbers follow the same logic.

Adjacent Data entry

The most common technique of performing data entry requires that you know
the sequence of columns of the table in which you want to enter data. With
this subsequent list in mind, enter the value of each field in its correct
position.

During data entry on adjacent fields, if you don't have a value for a numeric
field, you should type 0 as its value. For a string field whose data you don't
have and cannot provide, type two single-quotes to specify an empty field.
Here is an example:

C# 3.0 Practical Learning II 309


using System;
using ADODB;

public class Program


{
static int Main()
{
string strSQL;
object obj = new object();
ADOX.Catalog catPeople = new ADOX.Catalog();
ADODB.Connection conPeople = new ADODB.Connection();

try
{
conPeople.Open("Provider=Microsoft.Jet.OLEDB.4.0;" +
"Data
Source='C:\\Programs\\People.mdb'", "", "", 0);
conPeople.Execute("INSERT INTO Persons(FirstName,
LastName, Gender) " +
"VALUES('James', 'Carlton',
'Male');", out obj, 0);
Console.WriteLine("A new record has been created in
the Persons table");
}
finally
{
conPeople.Close();
}

return 0;
}
}

Random Data Entry

The adjacent data entry requires that you know the position of each column.
The SQL provides an alternative that allows you to perform data entry using
the name of a column instead of its position. This allows you to provide the
values of fields in any order of your choice.

To perform data entry at random, you must provide a list of the columns of
the table in the order of your choice. You can either use all columns or
provide a list of the same columns but in your own order. Here is an example:
using System;
using ADODB;

public class Program


{
static int Main()
{
string strSQL;
object obj = new object();
ADOX.Catalog catPeople = new ADOX.Catalog();

C# 3.0 Practical Learning II 310


ADODB.Connection conPeople = new ADODB.Connection();

try
{
conPeople.Open("Provider=Microsoft.Jet.OLEDB.4.0;" +
"Data
Source='C:\\Programs\\People.mdb'", "", "", 0);
conPeople.Execute("INSERT INTO Persons(LastName,
Gender, FirstName) " +
"VALUES('Germain', 'Male',
'Ndongo');", out obj, 0);
Console.WriteLine("A new record has been created in
the Persons table");
}
finally
{
conPeople.Close();
}

return 0;
}
}

You don't have to provide data for all columns, just those you want, in the
order you want. To do this, enter the names of the desired columns on the
right side of the name of the table, in parentheses. The syntax used would
be:
INSERT TableName(ColumnName1, Columnname2, ColumnName_n)
VALUES(ValueFormColumnName1, ValueFormColumnName2,
ValueFormColumnName_n);

Data Entry Assistance


 

The Nullity of a Field

When performing data entry, you can expect the user to skip any column
whose value is not available and move to the next. In some cases, you may
require that the value of a column be specified before the user can move on.
If you are creating a column and if you want to let the user add or not add a
value for the column, type the NULL keyword on the right side of the data
type. If you want to require a value for the column, type NOT NULL. Here are
examples:
using System;
using ADODB;

public class Program


{
static int Main()

C# 3.0 Practical Learning II 311


{
ADOX.Catalog catADOX = new ADOX.Catalog();

catADOX.Create("Provider=Microsoft.Jet.OLEDB.4.0;" +
"Data
Source='C:\\Programs\\VideoCollection.mdb';");
Console.WriteLine("A new Microsoft JET database named
VideoCollection.mdb " +
"has been created");

ADODB.Connection conVideos = new ADODB.Connection();


object obj = new object();

conVideos.Open("Provider=Microsoft.Jet.OLEDB.4.0;" +
"Data
Source='C:\\Programs\\VideoCollection.mdb'",
"", "", 0);
conVideos.Execute("CREATE TABLE Videos(" +
"VideoTitle STRING NOT NULL, " +
"Director STRING NULL, " +
"YearReleased SHORT, " +
"Rating BYTE NULL);",
out obj, 0);
Console.WriteLine("A new table named Videos has been
created");
conVideos.Close();

return 0;
}
}

In this case, when performing data entry, the user must always provide a
value for the VideoTitle column in order to create a record. If you omit to
specify the nullity of a field, it is assumed NULL; that's the case for the
YearReleased column of the above Videos table.

Auto-Increment

When we study relationships, we will see that, on a table, each record should
be uniquely identified. This should be the case even if many records seem to
have the same values for each column. We saw already that you can require
that the user provide a value for each record of a certain column. In some
cases, the user may not have the right value for a column but at the time, the
record would need to be created, even if it is temporary. To solve this type of
problem and many others, you can create a column that provides its own
value. On the other hand, to create a special column that can be used to
uniquely identify each record, you can apply an integer data type to it but ask
the database engine to automatically provide a numeric value for the column.

If you are creating the column, you can specify its data type as either
COUNTER or AUTOINCREMENT. Only one column of a table can have one of
these data types. Here is an example:

C# 3.0 Practical Learning II 312


using System;
using ADODB;

public static class Program


{
static int Main()
{
ADODB.Connection conVideos = new ADODB.Connection();
object obj = new object();

conVideos.Open("Provider=Microsoft.Jet.OLEDB.4.0;" +
"Data
Source='C:\\Programs\\VideoCollection.mdb'",
"", "", 0);
conVideos.Execute("CREATE TABLE Videos(" +
"ShelfNumber COUNTER, " +
"VideoTitle STRING NOT NULL, " +
"Director STRING NULL, " +
"YearReleased SHORT, " +
"Rating BYTE NULL);",
out obj, 0);
Console.WriteLine("A new table named Videos has been
created");
conVideos.Close();

return 0;
}
}

By default, when you apply the COUNTER or the AUTOINCREMENT data type,
when the user creates the first record, the field int the auto-incrementing
column receives a number of 1. If the user creates a second record, the auto-
incrementing value receives a number of 2, and so on. If you want, you can
make the first record receive a number other than 1. You can also make it
increment to a value other than 1. To apply this feature, the COUNTER and the
AUTOINCREMENT types use a seed as their parentheses:

COUNTER(x,y)

or
AUTOINCREMENT(x,y)

The x value represents the starting value of the records. The y value specifies
how much would be added to a value to get the next.

Fields Sizes

When reviewing the data types available for columns, we saw that some of
them could use a string-based data type, namely TEXT, CHAR, or VARCHAR. By
default, if you create a table and you set a column's data type to TEXT, CHAR,
or VARCHAR, it is made to hold 255 characters. If you want, you can control

C# 3.0 Practical Learning II 313


the maximum number of characters that would be allowed in a column during
data entry.

To specify the number of characters of the string-based column, add the


parentheses to the TEXT, the CHAR, or the VARCHAR data types, and in the
parentheses, enter the desired number. Here are examples:
using System;
using ADODB;

public static class Program


{
static int Main()
{
ADODB.Connection conVideos = new ADODB.Connection();
object obj = new object();

conVideos.Open("Provider=Microsoft.Jet.OLEDB.4.0;" +
"Data
Source='C:\\Programs\\VideoCollection.mdb'",
"", "", 0);
conVideos.Execute("CREATE TABLE Videos(" +
"ShelfNumber COUNTER, " +
"VideoTitle STRING(120) NOT NULL,
" +
"Director VARCHAR(80) NULL, " +
"YearReleased SHORT, " +
"Rating TEXT(20) NULL);",
out obj, 0);
Console.WriteLine("A new table named Videos has been
created");

conVideos.Close();

return 0;
}
}

Default Values

A default value allows a column to use a value that is supposed to be


common to most cells of a particular column. The default value can be set as
a constant value or it can use a function that would adapt to the time the
value is needed.

To specify a default value, after the name and the data type of a column,
type DEFAULT and assign it the desired value, based on the data type. Here is
an example:
using System;
using ADODB;

C# 3.0 Practical Learning II 314


public static class Program
{
static int Main()
{
ADODB.Connection conVideos = new ADODB.Connection();
object obj = new object();

conVideos.Open("Provider=Microsoft.Jet.OLEDB.4.0;" +
"Data
Source='C:\\Programs\\VideoCollection.mdb'",
"", "", 0);
conVideos.Execute("CREATE TABLE Videos(" +
"ShelfNumber COUNTER, " +
"VideoTitle STRING(120) NOT NULL, "
+
"Director VARCHAR(80) NULL, " +
"YearReleased SHORT, " +
"Rating TEXT(20) NULL
Default='PG-13')",
out obj, 0);
Console.WriteLine("A new table named Videos has been
created");
conVideos.Close();

return 0;
}
}

C# 3.0 Practical Learning II 315


Mathematics in C#
 

Overview of Numbers
 

Introduction

If you consider it in the purest sense of a computer language like C, C++,


Pascal, Visual Basic, and Java, etc, C# doesn't have its own built-in support
for mathematics. It must borrow this functionality either from other libraries
or from other language. Fortunately, all of this is particularly easy.

To perform the basic algebraic and geometric operations in C#, you can use
methods of the Math class of the .NET Framework. As seen in the previous
lesson, you can also take advantage of Visual Basic's very powerful library of
functions. This library is one of the most extended set of functions of various
area of business mathematics.

In Lesson 1, we saw different ways to declare a variable of a numeric type.


Here are examples:
using System;

class Program
{
static int Main()
{
short sNumber;
int iNumber;
double dNumber;
decimal mNumber;

return 0;
}
}

The Sign of a Number

One of the primary rules to observe in C# is that, after declaring a variable,


before using it, it must have been initialized. Here are examples of initializing
variables:
using System;

C# 3.0 Practical Learning II 316


class Program
{
static int Main()
{
short sNumber = 225;
int iNumber = -847779;
double dNumber = 9710.275D;
decimal mNumber = 35292742.884295M;

Console.WriteLine("Short Integer: {0}", sNumber);


Console.WriteLine("Integral Number: {0}", iNumber);
Console.WriteLine("Double-Precision: {0}", dNumber);
Console.WriteLine("Extended Precision: {0}", mNumber);

return 0;
}
}

This would produce:


Short Integer: 225
Integral Number: -847779
Double-Precision: 9710.275
Extended Precision: 35292742.884295
Press any key to continue . . .

When initializing a variable using a constant, you decide whether it is


negative, 0 or positive. This is referred to as its sign. If you are getting the
value of a variable some other way, you may not know its sign. Although you
can use comparison operators to find this out, the Math class provides a
method to check it out for you.

To find out about the sign of a value or a numeric variable, you can call the
Math.Sign() method. It is overloaded in various versions whose syntaxes are:
public static int Sign(sbyte value);
public static int Sign(short value);
public static int Sign(int value);
public static int Sign(long value);
public static int Sign(sbyte value);
public static int Sign(double value);
public static int Sign(decimal value);

When calling this method, pass the value or the variable you want to
consider, as argument. The method returns:

 -1 if the argument is negative

 0 if the argument is 0

 1 if the argument is positive

Here are examples of calling the method:


using System;

C# 3.0 Practical Learning II 317


class Program
{
static int Main()
{
short sNumber = 225;
int iNumber = -847779;
double dNumber = 9710.275D;
decimal mNumber = 35292742.884295M;

Console.WriteLine("Number: {0} => Sign: {1}",


sNumber, Math.Sign(sNumber));
Console.WriteLine("Number: {0} => Sign: {1}",
iNumber, Math.Sign(iNumber));
Console.WriteLine("Number: {0} => Sign: {1}",
dNumber, Math.Sign(dNumber));
Console.WriteLine("Number: {0} => Sign: {1}\n",
mNumber, Math.Sign(mNumber));

return 0;
}
}

This would produce:


Number: 225 => Sign: 1
Number: -847779 => Sign: -1
Number: 9710.275 => Sign: 1
Number: 35292742.884295 => Sign: 1

Press any key to continue . . .

The Integral Side of a Floating-Point Number

As reviewed in Lesson 1, when dealing with a floating-point number, it


consists of an integral side and a precision side; both are separated by a
symbol which, in US English, is the period. In some operations, you may want
to get the integral side of the value. The Math class can assist you with this.

To get the integral part of a decimal number, the Math class can assist you
with the Trancate() method, which is overloaded in two versions whose
syntaxes are:
public static double Truncate(double d);
public static double Truncate(double d);

When calling this method, pass it a number or a variable of float, double, or


decimal type. The method returns the int side of the value. Here is an
example of calling it:
using System;

class Program
{

C# 3.0 Practical Learning II 318


static int Main()
{
float number = 225.75f;

Console.WriteLine("The integral part of {0} is {1}\n",


number, Math.Truncate(number));

return 0;
}
}

This would produce:


The integral part of 225.75 is 225

Press any key to continue . . .

The Minimum of Two Values

If you have two numbers, you can find the minimum of both without writing
your own code. To assist you with this, the Math class is equipped with a
method named Min. This method is overloaded in various versions with each
version adapted to each integral or floating-point data type. The syntaxes
are:
public static byte Min(byte val1, byte val2);
public static sbyte Min(sbyte val1, sbyte val2);
public static short Min(short val1, short val2);
public static ushort Min(ushort val1, ushort val2);
public static int Min(int val1, int val2);
public static uint Min(uint val1, uint val2);
public static float Min(float val1, float val2);
public static long Min(long val1, long val2);
public static ulong Min(ulong val1, ulong val2);
public static double Min(double val1, double val2);
public static decimal Min(decimal val1, decimal val2);

Here is an example of calling the method:


using System;

class Program
{
static int Main()
{
int number1 = 8025;
int number2 = 73;

Console.WriteLine("The minimum of {0} and {1} is {2}",


number1, number2, Math.Min(number1, number2));

return 0;
}
}

C# 3.0 Practical Learning II 319


This would produce:
The minimum of 8025 and 73 is 73
Press any key to continue . . .

The Maximum Integer Value of a Series

As opposed to the minimum of two numbers, you may be interested in the


higher of both. To help you find the maximum of two numbers, you can call
the Max() method of the Math class. It is overloaded in various versions with
one of each type of numeric data. The syntaxes of this method are:
public static byte Max(byte val1, byte val2);
public static sbyte Max(sbyte val1, sbyte val2);
public static short Max(short val1, short val2);
public static ushort Max(ushort val1, ushort val2);
public static int Max(int val1, int val2);
public static uint Max(uint val1, uint val2);
public static float Max(float val1, float val2);
public static long Max(long val1, long val2);
public static ulong Max(ulong val1, ulong val2);
public static double Max(double val1, double val2);
public static decimal Max(decimal val1, decimal val2);

Here is an example of calling the method:


using System;

class Program
{
static int Main()
{
int number1 = 8025;
int number2 = 73;

Console.WriteLine("The maximum of {0} and {1} is {2}",


number1, number2, Math.Max(number1, number2));

return 0;
}
}

This would produce:


The maximum of 8025 and 73 is 8025
Press any key to continue . . .

Value Conversions
 

Implicit Conversions

C# 3.0 Practical Learning II 320


In Lesson 1, we saw how to declare variables of integral, floating-point, and
string types. We also saw how to initialize the variables. If you have a
program with mixed types of variables, you may be interested in converting
the value of one into another. Again, in Lesson 1, we saw how much memory
space the variable of each data type required in order to hold its value. Here
is a summary of what we learned:

Memory
Data Type Name
Size

byte Byte 8 bits

sbyte Signed Byte 8 bits

char Character 16 bits

short Small Integer 16 bits

ushort Unsigned Small Integer 16 bits

int Signed Integer 32 bits

uint Unsigned Integer 32 bits

float Single-Precision Floating-Point Number 32 bits

double Double-Precision Floating-Point Number 64 bits

long Signed Long Integer 64 bits

ulong Unsigned Long Integer 64 bits

Extended Precision Floating-Point


decimal 128 bits
Number

As you can see, a value held by a Byte variable can fit in the memory
reserved for an int variable, which can be carried by a long variable. Thanks
to this, you can assign a Byte value to an int variable, or an int variable to a
long variable. Also, based on this, because the memory reserved for an int

C# 3.0 Practical Learning II 321


variable is larger than the one reserved for a double variable, you can assign
a variable of the former to a variable of the latter. Here is an example:
using System;

class Program
{
static int Main()
{
int iNumber = 2445;
double dNumber = iNumber;

Console.WriteLine("Number = {0}", iNumber);


Console.WriteLine("Number = {0}\n", dNumber);
return 0;
}
}

This would produce:


Number = 2445
Number = 2445

Press any key to continue . . .

This characteristic is referred to as implicit conversion.

Explicit Conversions

Because of memory requirements, the direct reverse of implicit conversion is


not possible. Since the memory reserved for a short variable is smaller than
that of an int, you cannot assign the value of an int to a short variable.
Consider the following program:
using System;

class Program
{
static int Main()
{
int iNumber = 168;
short sNumber = iNumber;

Console.WriteLine("Number = {0}", iNumber);


Console.WriteLine("Number = {0}\n", sNumber);
return 0;
}
}

This would produce the following error:


Cannot implicitly convert type 'int' to 'short'.

C# 3.0 Practical Learning II 322


Value casting consists of converting a value of one type into a value of
another type. For example, you may have an integer value and you may want
that value in an expression that expects a short. Value casing is also referred
to as explicit conversion.

To cast a value or a variable, precede it with the desired data type in


parentheses. Here is an example:
using System;

class Program
{
static int Main()
{
int iNumber = 168;
short sNumber = (short)iNumber;

Console.WriteLine("Number = {0}", iNumber);


Console.WriteLine("Number = {0}\n", sNumber);
return 0;
}
}

This would produce:


Number = 168
Number = 168

Press any key to continue . . .

When performing explicit conversion, you should pay close attention to the
value that is being cast. If you want an integer value to be assigned to a
short variable, the value must fit in 16 bits, which means it must be between
-32768 and 32767. Any value beyond this range would proceed an
unpredictable result. Consider the following program:
using System;

class Program
{
static int Main()
{
int iNumber = 680044;
short sNumber = (short)iNumber;

Console.WriteLine("Number = {0}", iNumber);


Console.WriteLine("Number = {0}\n", sNumber);
return 0;
}
}

This would produce:


Number = 680044
Number = 24684

C# 3.0 Practical Learning II 323


Press any key to continue . . .

Notice that the result is not reasonable.

The Convert Class

In Lesson 6 and Lesson 17, we saw that each C# data type, which is
adapted from a .NET Framework structure, was equipped with a ToString()
method that could be used to convert its value to a String type. We didn't
address the possibility of converting a value from one primitive type to
another. To support the conversion of a value from one type to another,
the .NET Framework provides a class named Convert. This class is equipped
with various static methods; they are so numerous that we cannot review all
of them.
Remember that each primitive data type of the C# language is type-defined from
a .NET Framework structure as follows:

.NET
C# Data Type Name Framework
Structure

bool Bollean Boolean

byte Byte Byte

sbyte Signed Byte SByte

char Character Char

short Small Integer Int16

Unsigned Small
ushort UInt16
Integer

int Integer Int32

uint Unsigned Integer UInt32

long Long Integer Int64

C# 3.0 Practical Learning II 324


Unsigned Long
ulong UInt64
Integer

Single-Precision
float Single
Floating-Point

Double-Precision
double Double
Floating-Point

Extended Precision
decimal Floating-Point Decimal
Number

No Explicit Type Date/Time Value DateTime

string String String

To adapt the Convert class to each C# data type, the class is equipped with
a static method whose name starts with To, ends with the .NET Framework
name of its structure, and takes as argument the type that needs to be
converted. Based on this, to convert a decimal number of a double type to a
number of int type, you can call the ToInt32() method and pass the
double variable as argument. Its syntax is:

public static int ToInt32(double value);

Here is an example:
using System;

class Program
{
static int Main()
{
double dNumber = 34987.68D;
int iNumber = Convert.ToInt32(dNumber);

Console.WriteLine("Number: {0}", dNumber);


Console.WriteLine("Number: {0}", iNumber);
return 0;
}
}

Arithmetic

C# 3.0 Practical Learning II 325


 

Absolute Values

The decimal numeric system counts from negative infinity to positive infinity.
This means that numbers are usually negative or positive, depending on their
position from 0, which is considered as neutral. In some operations, the
number considered will need to be only positive even if it is provided in a
negative format. The absolute value of a number x is x if the number is
(already) positive. If the number is negative, its absolute value is its positive
equivalent. For example, the absolute value of 12 is 12, while the absolute
value of –12 is 12.

To get the absolute value of a number, the Math class is equipped with a
method named Abs, which is overloaded in various versions. Their syntaxes
are:
public static sbyte Abs(sbyte value);
public static short Abs(short value);
public static int Abs(int value);
public static float Abs(float value);
public static double Abs(double value);
public static long Abs(long value);
public static decimal Abs(decimal value);

This method takes the argument whose absolute value must be fond. Here is
an example:
using System;

class Program
{
static int Main()
{
int number = -6844;

Console.WriteLine("Original Value = {0}", number);


Console.WriteLine("Absolute Value = {0}\n",
Math.Abs(number));
return 0;
}
}

This would produce:


Original Value = -6844
Absolute Value = 6844

Press any key to continue . . .

The Ceiling of a Number

C# 3.0 Practical Learning II 326


Consider a floating-point number such as 12.155. This number is between
integer 12 and integer 13:

In the same way, consider a number such as –24.06. As this number is


negative, it is between –24 and –25, with –24 being greater.

In arithmetic, the ceiling of a number is the closest integer that is greater or


higher than the number considered. In the first case, the ceiling of 12.155 is
13 because 13 is the closest integer greater than or equal to 12.155. The
ceiling of –24.06 is –24.

To support the finding of a ceiling, the Math class is equipped with a method
named Ceiling that is overloaded with two versions whose syntaxes are:
public static double Ceiling(double a);
public static decimal Ceiling(decimal d);

This method takes as argument a floating-point number of variable whose


ceiling needs to be found. Here is an example:
using System;

class Program
{
static int Main()
{
double value1 = 155.55; double value2 = -24.06;

Console.WriteLine("The ceiling of {0} is {1}",


value1, Math.Ceiling(value1));
Console.WriteLine("The ceiling of {0} is {1}\n",
value2, Math.Ceiling(value2));
return 0;
}
}

This would produce:


The ceiling of 155.55 is 156
The ceiling of -24.06 is -24

Press any key to continue . . .

Besides the Math class, the Double structure provides its own implementation
of this method using the following syntax:
public static decimal Ceiling(decimal d);

The Floor of a Number

C# 3.0 Practical Learning II 327


Consider two floating numbers such as 128.44 and -36.72. The number
128.44 is between 128 and 129 with 128 being the lower. The number –36.72
is between –37 and –36 with –37 being the lower. The lowest but closest
integer value of a number is referred to as its floor.

To assist you with finding the floor of a number, the Math class provides the
Floor() method. It is overloaded in two versions whose syntaxes are:

public static double Floor(double d);


public static decimal Floor(decimal d);

The floor() method takes the considered value as the argument and returns
the integer that is less than or equal to Value. Here is an example:
using System;

class Program
{
static int Main()
{
double value1 = 1540.25;
double value2 = -360.04;

Console.WriteLine("The floor of {0} is {1}",


value1, Math.Floor(value1));
Console.WriteLine("The floor of {0} is {1}\n",
value2, Math.Floor(value2));
return 0;
}
}

This would produce:


The floor of 1540.25 is 1540
The floor of -360.04 is -361

Press any key to continue...

Instead of using the Math class, the Double structure also has a method to
find the floor of a decimal number. Its syntax is:
public static decimal Ceiling(decimal d);

The Power of a Number

The power is the value of one number or expression raised to another


number. This follows the formula:
ReturnValue = xy

To support this operation, the Math class is equipped with a method named
Pow whose syntax is

C# 3.0 Practical Learning II 328


public static double Pow(double x, double y);

This method takes two arguments. The first argument, x, is used as the base
number to be evaluated. The second argument, y, also called the exponent,
will raise x to this value. Here is an example:
using System;

class Program
{
static int Main()
{
const double source = 25.38;
const double exp = 3.12;

double result = Math.Pow(source, exp);

Console.WriteLine("Pow({0}, {1}) = {2}\n",


source, exp, result);
return 0;
}
}

This would produce:


Pow(25.38, 3.12) = 24099.8226934415

Press any key to continue . . .

The Exponential

You can calculate the exponential value of a number. To support this, the
Math class provides the Exp() method. Its syntax is:
public static double Exp (double d);

Here is an example of calling this method:


using System;

class Program
{
static int Main()
{
Console.WriteLine("The exponential of {0} is {1}",
709.78222656, Math.Exp(709.78222656));

return 0;
}
}

This would produce:


The exponential of 709.78222656 is 1.79681906923757E+308
Press any key to continue . . .

C# 3.0 Practical Learning II 329


If the value of x is less than -708.395996093 (approximately), the result is
reset to 0 and qualifies as underflow. If the value of the argument x is greater
than 709.78222656 (approximately), the result qualifies as overflow.

The Natural Logarithm

To calculate the natural logarithm of a number, you can call the Math.Log()
method. It is provides in two versions. The syntax of one is:
public static double Log(double d);

Here is an example:
using System;

class Program
{
static int Main()
{
double log = 12.48D;

Console.WriteLine("Log of {0} is {1}", log,


Math.Log(log));

return 0;
}
}

This would produce:


Log of 12.48 is 2.52412736294128
Press any key to continue . . .

The Base 10 Logarithm

The Math.Log10() method calculates the base 10 logarithm of a number.


The syntax of this method is:
public static double Log10(double d);

The number to be evaluated is passed as the argument. The method returns


the logarithm on base 10 using the formula:
y = log10x

which is equivalent to
x = 10y

Here is an example:
using System;

class Program

C# 3.0 Practical Learning II 330


{
static int Main()
{
double log10 = 12.48D;

Console.WriteLine("Log of {0} is {1}", log10,


Math.Log10(log10));

return 0;
}
}

This would produce:


Log of 12.48 is 1.09621458534641
Press any key to continue . . .

The Logarithm of Any Base 

The Math.Log() method provides another version whose syntax is:


public static double Log(double a, double newBase);

The variable whose logarithmic value will be calculated is passed as the first
argument to the method. The second argument allows you to specify a base
of your choice. The method uses the formula:
Y = logNewBasex

This is the same as


x = NewBasey

Here is an example of calling this method:


using System;

class Program
{
static int Main()
{
double logN = 12.48D;

Console.WriteLine("Log of {0} is {1}", logN,


Math.Log(logN, 4));

return 0;
}
}

This would produce:


Log of 12.48 is 1.82077301454376
Press any key to continue . . .

C# 3.0 Practical Learning II 331


The Square Root

You can calculate the square root of a decimal positive number. To support
this, the Math class is equipped with a method named Sqrt whose syntax is:
public static double Sqrt(double d);

This method takes one argument as a positive floating-point number. After


the calculation, the method returns the square root of x:
using System;

class Program
{
static int Main()
{
double sqrt = 8025.73D;

Console.WriteLine("The square root of {0} is {1}", sqrt,


Math.Sqrt(sqrt));

return 0;
}
}

This would produce:


The square root of 8025.73 is 89.5864387058666
Press any key to continue . . .

Trigonometry
 

Introduction

A circle is a group or series of distinct points drawn at an exact same distance


from another point referred to as the center. The distance from the center C
to one of these equidistant points is called the radius, R. The line that
connects all of the points that are equidistant to the center is called the
circumference of the circle. The diameter is the distance between two points
of the circumference to the center; in other words, a diameter is double the
radius.

C# 3.0 Practical Learning II 332


To manage the measurements and other related operations, the
circumference is divided into 360 portions. Each of these portions is called a
degree. The unit used to represent the degree is the degree, written as ˚.
Therefore, a circle contains 360 degrees, that is 360˚. The measurement of
two points A and D of the circumference could have 15 portions of the
circumference. In this case, this measurement would be represents as 15˚.

The distance between two equidistant points A and B is a round shape


geometrically defined as an arc. An angle, ө, is the ratio of the distance
between two points A and B of the circumference divided by the radius R.
This can be written as:

Therefore, an angle is the ratio of an arc over the radius. Because an angle is
a ratio and not a “physical” measurement, which means an angle is not a
dimension, it is independent of the size of a circle. Obviously this angle
represents the number of portions included by the three points. A better unit
used to measure an angle is the radian or rad.

A cycle is a measurement of the rotation around the circle. Since the rotation
is not necessarily complete, depending on the scenario, a measure is made
based on the angle that was covered during the rotation. A cycle could cover
part of the circle in which case the rotation would not have been completed.
A cycle could also cover the whole 360˚ of the circle and continue there after.
A cycle is equivalent to the radian divided by 2 * Pi.

The Pi Constant

The word п, also written as Pi, is a constant number used in various


mathematical calculations. Its approximate value is 3.1415926535897932.
The calculator of Windows represents it as
3.1415926535897932384626433832795. Borland had included its value in the
math.h library as M_PI 3.14159265358979323846.

A diameter is two times the radius. In geometry, it is written as 2R. In C++, it


is written as 2 * R or R * 2 (because the multiplication is symmetric). The

C# 3.0 Practical Learning II 333


circumference of a circle is calculated by multiplying the diameter to Pi, which
is 2Rп, or 2 * R * п or 2 * R * Pi.

A radian is 2Rп/R radians or 2Rп/R rad, which is the same as 2п rad or 2 * Pi


rad.

To perform conversions between the degree and the radian, you can use the
formula:

360˚ = 2п rad which is equivalent to 1 rad = 360˚ / 2п = 57.3˚.

The Cosine of a Value

Consider the following geometric figure:

  

Consider AB the length of A to B, also referred to as the hypotenuse. Also


consider AC the length of A to C which is the side adjacent to point A. The
cosine of the angle at point A is the ratio AC/AB. That is, the ratio of the
adjacent length, AC, over the length of the hypotenuse, AB:

The returned value, the ratio, is a double-precision number between –1 and


1.

To calculate the cosine of an angle, the Math class provides the Cos()
method. Its syntax is:
public static double Cos(double d);

Here is an example:
using System;

class Program
{
static int Main()
{
int number = 82;

Console.WriteLine("The cosine of {0} is {1}", number,


Math.Cos(number));

C# 3.0 Practical Learning II 334


return 0;
}
}

This would produce:


The cosine of 82 is 0.949677697882543
Press any key to continue . . .

The Sine of a Value

Consider AB the length of A to B, also called the hypotenuse to point A. Also


consider CB the length of C to B, which is the opposite side to point A. The
sine represents the ratio of CB/AB; that is, the ratio of the opposite side, CB
over the hypotenuse AB.

To calculate the sine of a value, you can call the Sin() method of the Math
class. Its syntax is:
public static double Sin(double a);

Here is an example:
using System;

class Program
{
static int Main()
{
double number = 82.55;

Console.WriteLine("The sine of {0} is {1}", number,


Math.Sin(number));

return 0;
}
}

This would produce:


The sine of 82.55 is 0.763419622322519
Press any key to continue . . .

Tangents

Consider AC the length of A to C. Also consider BC the length of B to C. The


tangent is the result of BC/AC; that is, the ratio of BC over AC. To assist you
with calculating the tangent of of a number, the Math class is equipped with a
method named Tan whose syntax is:
public static double Tan(double a);

Here is an example:

C# 3.0 Practical Learning II 335


using System;

class Program
{
static int Main()
{
uint number = 225;

Console.WriteLine("The tangent of {0} is {1}", number,


Math.Tan(number));

return 0;
}
}

This would produce:


The tangent of 225 is -2.53211499233434
Press any key to continue . . .

The Arc Tangent

Consider BC the length of B to C. Also consider AC the length of A to C. The


arc tangent is the ratio of BC/AC. To calculate the arc tangent of a value, you
can use the Math.Atan() method. Its syntax is
public static double Atan(double d);

Here is an example:
using System;

class Program
{
static int Main()
{
short number = 225;

Console.WriteLine("The arc tangent of {0} is {1}",


number, Math.Atan(number));

return 0;
}
}

This would produce:


The arc tangent of 225 is 1.56635191161394
Press any key to continue . . .

C# 3.0 Practical Learning II 336


C# 3.0 Practical Learning II 337
Dates and Times
 

Dates and Times


 

Introduction

A date is a measure of non-spatial units that have elapsed in a set period. To


perform this measure, a certain point is set and called midnight. From that
point, a number of units are counted until the next corresponding point is
reached. Because the light in daily life changes from one midnight unit to the
next midnight unit, the sub-point when the light shows up, or starts, is called
sunrise. The sub-point when the light diminishes or starts disappearing is
called sunset. The midpoint between the sunrise and the sunset is called
noon. The first part, from midnight to noon is referred to as AM in US English.
The other part is referred to as PM in US English.

The group of units between two midnight points is called a day. The days are
counted from 0, 1, and up. A group of seven consecutive days is called a
week. The weeks are counted from 1 and up. To make it easy to identify a
day, the days of a week are named as Monday, Tuesday, Wednesday,
Thursday, Friday, Saturday, and Sunday. These are referred to as long
names. The corresponding short names are Mon, Tue, Wed, Thu, Fri, Sat,
and Sun. The day considered as the first of the week depends on the
language and/or some other considerations. For example, in US English,
Sunday is usually considered the first day of the week.

Most of the time, a group of four weeks is called a month. The months are
counted from 1 and up. To make it easy to identify a month, each holds a
long name and they are January, February, March, April, May, June, July,
August, September, October, November, and December. Their short names
are Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, and Dec. Except for
the month of February that depends on a factor named Leap Year, the
maximum days of each month are January=31, March=31, April=30,
May=31, June=30, July=31, August=31, September=30, October=31,
November=30, and December=31.

A group of three months is called a trimester. A group of four months is called


a quarter. A group of six months is called a semester. A group of twelve
months is called a year. The years are counted from 1 and up (some
compilers or applications specify when the years start; for example, some
applications start their count at 1901 and cannot process years below that

C# 3.0 Practical Learning II 338


numbers; some other applications would not process a year beyond a certain
year). The .NET Framework compilers count the years from 0001 to 9999.

In a regular year, the months are counted from 1 to 12. The technique or
expression used to identify a particular day during a year is called a date. The
days are counted from 1 to 365 or 366 (depending on a factor called a leap
year). A date can be the combination of a day, its months, and the year.
There are other aspects that can be taken into consideration. We will address
them when necessary.

A unit of measure in a day is called a second. The seconds are counted from
0 to 59 or from 0, 1, 2, and so on. In some applications, when precision is
particularly important, a second is considered a group of 1000 portions called
milliseconds. The milliseconds are counted from 0 to 999.

A group of 60 seconds is called a minute. A group of 60 minutes is called an


hour. A group of 24 hours is called a day. The technique or expression used
to identify a particular unit of measure during a day is called the time. It can
be the combination of the hour, the minute, and the second. Some other
aspects may be taken into consideration. We will review them as we move
on.

Date Time Value Creation

To represent the dates, computers, applications, and compilers are configured


with specific techniques. In Microsoft Windows, to manage dates, the
operating system provides a structure named SYSTEMTIME. To manage
dates, the .NET Framework provides the DateTime structure. To create a
date or a time value, you can first declare DateTime variable. To assist you
with initializing the variable, the DateTime structure is equipped with various
constructors.

The default constructor allows you to create a date or a time object without
specifying its details. This would be done as follows:

using System;

namespace DateAndTime
{
class Program
{
static int Main()
{
DateTime tm = new DateTime();

return 0;
}
}
}

C# 3.0 Practical Learning II 339


After declaring a DateTime variable and initializing it, it holds all necessary
pieces of information about its date and its time values.

The Characteristics of a Date-Time Value

You can access the information using the variable. The pieces of information
are represented by properties of the DateTime structure and they are:

 Month: The Month property is the numeric value, between 1 and 12, of
the month of the variable

 Day: The Day property is the numeric value of the day in the Month
value of the variable. Depending on the month, the value is between 1
and 31. For example, if the variable's value is April 6, 2002, the Day
value is 6

 DayOfWeek: The DayOfWeek property is the name of the Day value of


the variable. The name is a member of the DayOfWeek enumeration
whose members are Sunday, Monday, Tuesday, Wednesday, Thursday,
Friday, and Saturday. Because the members are listed without a re-
definition of their default indexes, the index of Sunday is 0 and the index
of Saturday is 6

 Year: The Year property is the numeric value of the year of the variable

 DayOfYear: The DayOfYear is the number that represents the ranking


day inside of the Year value of the variable. For example, if the
variable's value is February 6, 2002, the DayOfYear value is 31 + 6 = 37

 Date: The Date property is the combination of the Month, the Day, and
the Year values of the variable

 Hour: The Hour is the numeric value of the hour, between 0 and 23, of
the time component of the variable

 Minute: The Minute is the numeric value of the minute inside of the
Hour value of the variable. It is a value between 0 and 59 

 Second: The Second is the numeric value of the second inside of the
Minute value of the Hour value. It is a value between 0 and 59

 Millisecond: The Millisecond is the numeric value of the millisecond


inside of the Second value of the Minute part of the Hour section of the
variable. It is a value between 0 and 999

The Default Date and Time Values

C# 3.0 Practical Learning II 340


The default constructor of the DateTime structure initializes the date to
January 1st, 0001 and the time at midnight (01:01:01). This is illustrated in
the following program:
using System;

namespace DateAndTime
{
class Program
{
static int Main()
{
DateTime tm = new DateTime();

Console.WriteLine("Default Date and Time: {0}", tm);


return 0;
}
}
}

This would produce:


Default Date and Time: 1/1/0001 12:00:00 AM
Press any key to continue . . .

This also means that the lowest date and time values that a DateTime object
can hold is January 1st, 0001 at 00:00:00. This value is represented by the
MinValue constant member of the DateTime structure. The highest date and
time that a DateTime object can hold in the structure is called MaxValue and
it is set at December 31, 9999.

Dates
 

Date Creation

A date is a technique of identifying a period using three numbers: the year,


the month, and the day. Each is an integer value. If you know the values you
want to use to create or specify a date value, when declaring a DateTime
variable, you can use the following constructor:
public DateTime(int year, int month, int second);

Here is an example of creating a date:


using System;

namespace DateAndTime
{
class Program
{
static int Main()

C# 3.0 Practical Learning II 341


{
DateTime ind = new DateTime(1960, 1, 1);

Console.WriteLine("Independence Day: {0}", ind);


return 0;
}
}
}

This would produce:


Independence Day: 1/1/1960 12:00:00 AM
Press any key to continue . . .

Converting a String to Date

Before displaying a DateTime value in your application, you can first convert
it to a string. To support this, the DateTime structure provides the
ToString() method that is overloaded with various versions. One of the
versions takes no argument and its syntax is:
public override string ToString();

If you call this version of the method, the compiler uses a default format
depending on the language set on the user's computer. If you want to
control how the date should be rendered, you can use the version of the
ToString() method that takes as argument a String value.

Rules of Date Formats

The computer uses two main categories of date display. These categories are
based on the language used by your computer. For example, most user
computers that reside in the United States use a standard known as US
English. This commands how the date displays in the continental US. Each
category uses specific characters to represent its value:

Format Description

MM The double M (in uppercase) string gets the numeric value of


the month from 1 to 12. If the number is less than 10, it
would display with the leading 0. Here is an example:
using System;

namespace DateAndTime
{
class Program
{
static int Main()
{

C# 3.0 Practical Learning II 342


DateTime date = new DateTime(2002, 4,
22);
string strMonth = date.ToString("MM");

Console.WriteLine("Date and Time:


{0}", date);
Console.WriteLine("Month Value:
{0}\n", strMonth);
return 0;
}
}
}

This would produce:


Date and Time: 4/22/2002 12:00:00 AM
Month Value: 04

Press any key to continue . . .

It the number is higher than 9, it would display so.

MMM The triple M as MMM (in uppercase) gets the name of the
month using three letters. This variable is defined by the
operating system. The names of the month in US English are
Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, and
Dec. Here is an example:
using System;

namespace DateAndTime
{
class Program
{
static int Main()
{
DateTime date = new DateTime(1998, 1,
12);
string strMonth =
date.ToString("MMM");

Console.WriteLine("Date and Time:


{0}", date);
Console.WriteLine("Month Name:
{0}\n", strMonth);
return 0;
}
}
}

This would produce:


Date and Time: 1/12/1998 12:00:00 AM
Month Name: Jan

C# 3.0 Practical Learning II 343


Press any key to continue . . .

MMMM The quadruple M as MMMM (in uppercase) gets the complete


name of a month as defined by the operating system of the
user's computer. The names of the months are January,
February, March, April, May, June, July, August, September,
October, November, and December.
Here is an example:
using System;

namespace DateAndTime
{
class Program
{
static int Main()
{
DateTime date = new DateTime(2004, 10,
23);
string strMonth =
date.ToString("MMMM");

Console.WriteLine("Date and Time:


{0}", date);
Console.WriteLine("Month Name:
{0}\n", strMonth);
return 0;
}
}
}

This would produce:


Date and Time: 10/23/2004 12:00:00 AM
Month Name: October

Press any key to continue . . .

dd The double d gets the numeric day of the month. If the


number is less than 10, it would display with a leading 0. Here
is an example:
using System;

namespace DateAndTime
{
class Program
{
static int Main()
{
DateTime date = new DateTime(2002, 4,
2);
string strDay = date.ToString("dd");

C# 3.0 Practical Learning II 344


Console.WriteLine("Date and Time:
{0}", date);
Console.WriteLine("Month Value:
{0}\n", strDay);
return 0;
}
}
}

This would display:


Date and Time: 4/2/2002 12:00:00 AM
Month Value: 02

Press any key to continue . . .

yy The double y is used to get the numeric year with the last two
digits. Here is an example:
using System;

namespace DateAndTime
{
class Program
{
static int Main()
{
DateTime date = new DateTime(2002, 4,
2);
string strYear2Digits =
date.ToString("yy");

Console.WriteLine("Date and Time:


{0}", date);
Console.WriteLine("Year Value:
{0}\n", strYear2Digits);
return 0;
}
}
}

This would produce:


Date and Time: 4/2/2002 12:00:00 AM
Year Value: 02

Press any key to continue . . .

yyyy The yyyy string is used to get all four digits of a year. Here is
an example:
using System;

namespace DateAndTime
{

C# 3.0 Practical Learning II 345


class Program
{
static int Main()
{
DateTime date = new DateTime(2002, 4,
2);
string strYear4Digits =
date.ToString("yyyy");

Console.WriteLine("Date and Time:


{0}", date);
Console.WriteLine("Year Value:
{0}\n", strYear4Digits);
return 0;
}
}
}

This would produce:


Date and Time: 4/2/2002 12:00:00 AM
Year Value: 2002

Press any key to continue . . .

If the year was provided with two digits, such as 98, it would
still be produced with 4 digits. Consider the following
example:
using System;

namespace DateAndTime
{
class Program
{
static int Main()
{
DateTime date = new DateTime(98, 4,
2);
string strYear4Digits =
date.ToString("yyyy");

Console.WriteLine("Date and Time:


{0}", date);
Console.WriteLine("Year Value:
{0}\n", strYear4Digits);
return 0;
}
}
}

This would produce:


Date and Time: 4/2/0098 12:00:00 AM
Year Value: 0098

C# 3.0 Practical Learning II 346


Press any key to continue . . .

Notice that this may be a wrong date. For this reason, in your C#
applications, you should always make it a habit to (always) provide
your years with 4 digits.

Compilers  (as done in different implementations of


various languages (C++, Pascal, Visual Basic, Java,
SQL, Oracle, DB2, etc)), libraries (Win32, VCL, MFC,
etc), applications (Microsoft Excel, OpenOffice.Org,
Microsoft Access, Sun StarOffice, Quattro Pro, etc), and
programming environments (Borland Developer Studio)
have different ways of performing this operation. For
example, in Microsoft Excel, if you are using the
computer in the year 2006, if you provide a date value
that has a year set with two digits such as 98,
Microsoft Excel would add the two digits of the
previous century, in this 19, to produce 1998. If you
provide a year such as 02, the Microsoft Excel
interpreter would add the current century to produce
2002.

Date Formats
 

The Computer’s System of Displaying Dates

To display a date in an application, by default, the compiler checks the


Regional Options of the Control Panel. To see the options, from the Control
Panel, you can double-click Regional or Language Option. From the
Regional Options tab of the Regional or Language Option dialog box,
you can click Customize... In the Customize Regional Options dialog box, click
Date.

Getting a Date Value From a DateTime Object

You may have notice that, by default, a DateTime object always produces
both a date and a time. In some cases, you will be interested in only the date
portion of the object. To get a date value, you can call the
DateTime.ToString() method that takes a String as argument and apply some
rules:

C# 3.0 Practical Learning II 347


Format Description

  Empty Space: Between the components of a date value, you


are allowed to leave empty spaces if you want.
Don't pass an empty space to the ToString() method.

, Comma: To separate the sections of a date value, you can use


the comma.
Don't pass a comma by itself to the ToString() method.

/ Date Separator: The compiler refers to the Control Panel to


identify this character. In US English, the forward slash is used
to separate the portions of a date:

Don't pass the forward slash by itself to the ToString()


method.

Others: Dash and Others: Besides the forward slash, the user's
- . computer may allow other characters. For example, in US
English, the "-" can be used. You can check available

C# 3.0 Practical Learning II 348


characters in the Date Separator combo box of the Date tab of
the Customize Regional Options of the Control Panel.
Don't pass any of these characters by itself to the ToString()
method.

The other characters and their combinations (MM, MMM, MMMM, dd, yy, and
yyyy) are used as we reviewed them. 

Here are examples of displaying date formats:


using System;

namespace DateAndTime
{
class Program
{
static int Main()
{
DateTime date = new DateTime(2004, 10, 23);

Console.WriteLine("Date and Time: {0}", date);


Console.WriteLine(date.ToString("M/d/yyyy"));
Console.WriteLine(date.ToString("M/d/yy"));
Console.WriteLine(date.ToString("MM/dd/yy"));
Console.WriteLine(date.ToString("MM/dd/yyyy"));
Console.WriteLine(date.ToString("yy/MM/dd"));
Console.WriteLine(date.ToString("yyyy-MM-dd"));
Console.WriteLine(date.ToString("dd-MMM-yy"));
return 0;
}
}
}

This would produce:


10/15/2006
10/15/06
10/15/06
10/15/2006
06/10/15
2006-10-15
15-Oct-06
Press any key to continue . . .

The Short Date

Instead of creating your own format, the Microsoft Windows operating system
provides two names that can be used to identify a date. A date is referred to
as short if it includes (only) the numeric portions of the month and the day of
a date value. The operating systems follows the rules we have reviewed so
far for the numbers and the Date Separator. The possible formats of a short

C# 3.0 Practical Learning II 349


date can be seen in the Short Date Format combo box of the Date tab of the
Customize Regional Options of the Regional and Language Settings of the
Control Panel:

To get the Short Date of a DateTime object, pass a "d" (one d in lowercase)
string to the ToString() method. Here is an example:
using System;

namespace DateAndTime
{
class Program
{
static int Main()
{
DateTime date = new DateTime(2004, 10, 23);
string strDate = date.ToString("d");

Console.WriteLine("Date and Time: {0}", date);


Console.WriteLine("Date Portion: {0}\n", strDate);
return 0;
}
}
}

This would produce:

C# 3.0 Practical Learning II 350


Date and Time: 10/23/2004 12:00:00 AM
Date Portion: 10/23/2004

Press any key to continue . . .

The Long Date Format

A date is referred to as long if it includes the names of the month and the day
of the week of a date value. This is called the Long Date Format. To get the
Long Date of a date, pass a "D" (one d in uppercase) string to the
ToString() method of a DateTime object. Here is an example:

using System;

namespace DateAndTime
{
class Program
{
static int Main()
{
DateTime date = new DateTime(2004, 10, 23);
string strDate = date.ToString("D");

Console.WriteLine("Date and Time: {0}", date);


Console.WriteLine("Date Portion: {0}\n", strDate);
return 0;
}
}
}

To produce the result, the compiler refers to the Long Date Format combo
box of the Customize Regional Options of the Control Panel. The user can
change the format by selecting one from the combo box:

C# 3.0 Practical Learning II 351


Based on the default settings of a computer used in US English, the above
program would produce:
Date and Time: 10/23/2004 12:00:00 AM
Date Portion: Saturday, October 23, 2004

Press any key to continue . . .

Other Date Formats

The .NET Framework provides other formats, not regularly used but available.
To get the name of a month and the year value of a DateTime object, both
separated by an empty space, pass a single M (uppercase) as string to the
ToString() method of a DateTime object. Here is an example:

using System;

namespace DateAndTime
{
class Program
{
static int Main()
{
DateTime date = new DateTime(2004, 10, 23);

C# 3.0 Practical Learning II 352


string strDate = date.ToString("M");

Console.WriteLine("Date and Time: {0}", date);


Console.WriteLine("Month and Year: {0}\n", strDate);
return 0;
}
}
}

This would produce:


Date and Time: 10/23/2004 12:00:00 AM
Month and Year: October 23

Press any key to continue . . .

To include a comma in the result, pass a single y (lowercase) as string to the


ToString() method of a DateTime object. Here is an example:

using System;

namespace DateAndTime
{
class Program
{
static int Main()
{
DateTime date = new DateTime(2004, 10, 23);
string strDate = date.ToString("y");

Console.WriteLine("Date and Time: {0}", date);


Console.WriteLine("Month and Year: {0}\n", strDate);
return 0;
}
}
}

This would produce:


Date and Time: 10/23/2004 12:00:00 AM
Month and Year: October, 2004

Press any key to continue . . .

Operations on Dates
 

The Leap Year

One of the operations performed on date values is to find out whether the
year value of a date is a leap year. Fortunately, the static IsLeapYear()
method of the DateTime structure can be used to perform this operation. The
syntax of this function is:

C# 3.0 Practical Learning II 353


public static bool IsLeapYear(int year);

This method takes an integer argument and examines it. If the argument,
which must be a valid year number, is a leap year, the method returns true;
otherwise, it would return false. Here are two examples:
using System;

namespace DateAndTime
{
class Program
{
static int Main()
{
DateTime date = new DateTime(1988, 10, 6);
Console.WriteLine("{0} was a leap year: {1}",
date.Year,
DateTime.IsLeapYear(date.Year));

date = new DateTime(1990, 8, 12);


Console.WriteLine("{0} was a leap year: {1}",
date.Year,
DateTime.IsLeapYear(date.Year));

return 0;
}
}
}

This would produce:


1988 was a leap year: True
1990 was a leap year: False
Press any key to continue . . .

The Day of the Week

The DateTime structure is equipped with a property that can be used to


retrieve the day of the week for a given date. The property is named
DayOfWeek. To get the day of the week, access the DayOfWeek property a
your DateTime value or variable. The values are stored in the DayOfWeek
enumeration. Here is an example:
using System;

namespace DateAndTime
{
class Program
{
static int Main()
{
DateTime date = new DateTime(1988, 10, 6);

C# 3.0 Practical Learning II 354


Console.WriteLine("Day of the week: {0}",
date.DayOfWeek);

return 0;
}
}
}

This would produce:


Day of the week: Thursday
Press any key to continue . . .

A Time Span

Dates are some of the most important values of the operating system and
many applications need them to perform their routine operations. Common
operations include adding days to a date, subtracting months from a date,
adding years, comparing dates to find out whether one occurs before
another, finding out if a payroll falls on a holiday, etc. To perform some of
these operations, a unit called an interval is considered as part of a date. A
date interval is the number of days, months, or years that have elapsed, or
would elapse, from one starting date to another ending date. Once you have
specified this interval, you can then apply it to a date with the operation of
your choice.

To support the ability to perform operations on dates, the .NET Framework is


provides the TimeSpan structure. This structure is equipped with various
members that would be applied on the TimeSpan structure. The value
produced by this structure is then applied to a DateTime object. To create a
date interval, declare a TimeSpan variable and initialize it with the desired
value(s). To make this possible, the TimeSpan structure is equipped with
various constructors.

Adding and/or Subtracting Days

With the DateTime structure, you can add some days to an existing date or
subtract some days from a date value. To support this, the DateTime
structure is equipped with the AddDays() method. Its syntax is:
public DateTime AddDays(int days);

Here is an example of calling this method:


using System;

namespace DateAndTime
{
class Program
{
static int Main()

C# 3.0 Practical Learning II 355


{
DateTime startDate = new DateTime(1988, 10, 6);
Console.WriteLine("Starting Date: {0}", startDate);

// This will be used to add 8 days to the previous


date
DateTime endDate = startDate.AddDays(8);
// And display it
Console.WriteLine("Ending Date: {0}\n", endDate);

return 0;
}
}
}

This would produce:


Starting Date: 10/6/1988 12:00:00 AM
Ending Date: 10/14/1988 12:00:00 AM

Press any key to continue . . .

If you pass a positive value to the DateTime.AddDays() method, a number


of days is added to the DateTime variable. If you want to subtract some days
from a date, pass the argument with a negative value. This method is able to
figure out the year before, the month before, the day before, the day after,
the month after, and the year after the designated date.

One of the constructors of the TimeSpan structure takes four arguments. Its
syntax
public TimeSpan(int days, int hours, int minutes, int seconds);

The first argument of this constructor represents the number of days. If you
are planning to add a number of days to a date, pass a positive integer as the
first argument. If you want to subtract a date, pass a negative value. If you
want to add only a number of days, pass only this argument.

After creating a TimeSpan object, you can call the Add() method of the
DateTime structure to a date value. This would produce a new DateTime
object that is the resulting value. Here are examples:
using System;

namespace DateAndTime
{
class Program
{
static int Main()
{
DateTime startDate = new DateTime(1988, 10, 6);
Console.WriteLine("Starting Date: {0}\n",
startDate);

C# 3.0 Practical Learning II 356


// This will be used to add 172 days to the previous
date
TimeSpan ts = new TimeSpan(172, 0, 0, 0);
// Pass the TimeSpan object to the date
DateTime endDate = startDate.Add(ts);
// And display it
Console.WriteLine("Ending Date: {0}\n", endDate);

// Subtract 10 days to the previous date


ts = new TimeSpan(-10, 0, 0, 0);
// Pass the TimeSpan object to the date
endDate = startDate.Add(ts);
// And display it
Console.WriteLine("Ending Date: {0}\n", endDate);

return 0;
}
}
}

This would produce:


Starting Date: 10/6/1988 12:00:00 AM

Ending Date: 3/27/1989 12:00:00 AM

Ending Date: 9/26/1988 12:00:00 AM

Press any key to continue . . .

Notice that, when adding or subtracting days, the complier can figure out the
previous day, the previous month, the previous year, the following day, the
following month, or the following year.

Adding or Subtracting Months to a Date

To add a number of months to a date, the DateTime class is equipped with a


method named AddMonths(). Its syntax is:
public DateTime AddMonths(int months);

This method takes one argument as the number of months to be added or


subtracted. If you pass the argument with a positive value, the months are
added to the date. If you pass a negative value, the number of months is
subtracted from the date.

Adding or Subtracting Years to a Date

To get the date a few years before or after a known date, you can add years
to, or subtract years from, a known date. To support this operation, the
DateTime class provides a method named AddYears(). Its syntax is:

public DateTime AddYears(int years);

C# 3.0 Practical Learning II 357


The argument passed to the method is the number of years. A positive value
(or a negative value) adds (or subtracts) the number of years to (or from) the
date.

Logical Operations on Dates

Using the logical operators we reviewed for primitive types, you can compare
the values of dates for equality, differences, lower or greater values. To
support these operations, the DateTime structure have the logical operators
configured.

To compare two dates, apply the desired Boolean operator the same day you
would two variables of primitive types. Here is an example:
using System;

namespace DateAndTime
{
class Program
{
static int Main()
{
DateTime startDate = new DateTime(1988, 10, 6);
Console.WriteLine("Starting Date: {0}", startDate);

// This will be used to add 8 days to the previous


date
DateTime endDate = startDate.AddDays(8);
// And display it
Console.WriteLine("Ending Date: {0}\n", endDate);

if (startDate < endDate)


Console.WriteLine("{0} Occurs Before {1}",
startDate, endDate);

return 0;
}
}
}

This would produce:


Starting Date: 10/6/1988 12:00:00 AM

Ending Date: 10/14/1988 12:00:00 AM

10/6/1988 12:00:00 AM Occurs Before 10/14/1988 12:00:00 AM


Press any key to continue . . .

Time
 

C# 3.0 Practical Learning II 358


Introduction

As defined earlier, the time is a value used to identify the number of units
that have elapsed since a starting period, called midnight, of a day. A day is
made of 24 non-spatial divisions; each one of these divisions is called an
hour. An hour is made of 60 fractions and each one of these fractions is called
a minute. A minute is divided in 60 parts, each called a second. As done with
dates, most of the operations performed on time values are centered around
the DateTime structure.

The rules used by the computer for time display can be seen in the Customize
Regional Options dialog box. To access it, in the Control Panel, you can
double-click Regional and Language Options. In the Regional Options tab of
the Regional and Language Options dialog box, you can click Customize. In
the Customize Regional Options, you can click Time:

In US English, the symbol to separate the hour and the minute. An example
would be: 08:25. In the same way, in US English, the character used to
separate the minute and the second is “:”. An example would be: 08:25 :44.
In many cases, unless necessary, the second is not represented in a time
value.

C# 3.0 Practical Learning II 359


The time of a day can be considered as a value of 24 hours or the day can be
considered as two fractions of 12 hours each. There is a period in the middle
of day time called noon. It divides the 24-hour day in two parts, each
consisting of 12 hours. The noon period is positioned 12 hours after midnight.
The period that goes from midnight to the middle of day time is represented
by the expression AM. The period from noon to midnight is represented by
the PM expression. When a DateTime object includes an AM or PM but of
unknown value, the section is represented as AM/PM and this expression is
written on the right side of the seconds. To separate the seconds and the
AM/PM, you (as well as the compiler) leave a one-character empty space after
the seconds.

Creating a Time Value

The time portion of a DateTime structure can be declared and manipulated as


a value. To create a time value, you can declare a DateTime variable using
the following constructor:
public DateTime(int year, int month, int day,
int hour, int minute, int second);

If you are more concerned about the time, the first, second, and third
arguments are not important. You can pass each as 1. In this case, the date
would be set as January 1, 0001. The other three arguments represent the
components of a time value.

The minutes value must range from 0 to 59; otherwise, an error would be
produced (when studying exception handling, we will see that this means that
the compiler would throw an exception). The seconds value must be between
0 and 59 or the program would cause an error.

When initializing a date or time variable using this constructor, the hour value
must be between 0 and 23. Any other value outside of this range will cause
an error. If the hour portion has a value between 0 and 11, the time is set in
the morning with the AM in the AM/PM section. Here is an example:
using System;

namespace DateAndTime
{
class Program
{
static int Main()
{
DateTime time = new DateTime(1, 1, 1, 10, 24, 52);

Console.WriteLine("Time: {0}\n", time);


return 0;
}
}
}

C# 3.0 Practical Learning II 360


This would produce:
Time: 1/1/0001 10:24:52 AM

Press any key to continue . . .

If the hour portion is between 12 and 23, the time is set in the afternoon.
When displaying it, the compiler, by default, calculates and displays the 0 to
12 portion and then displays PM in the AM/PM section. Here is an example:
using System;

namespace DateAndTime
{
class Program
{
static int Main()
{
DateTime time = new DateTime(1, 1, 1, 16, 8, 44);

Console.WriteLine("Time: {0}\n", time);


return 0;
}
}
}

This would produce:


Time: 1/1/0001 4:08:44 PM

Press any key to continue . . .

In extreme cases, you may want to use the milliseconds of a time value.
When declaring and initializing the variable, you can use the following
constructor:
public DateTime(int year, int month, int day,
int hour, int minute, int second, int
millisecond);

The milliseconds must range from 0 to 999. If you do not know the
millisecond value, you can provide it as 0.

Retrieving a Time Value

In a certain application, you may want the user to supply a time value. As
mentioned for the date, there are rules that you, the computer, and the user
must follow to apply a valid formula. As mentioned earlier, the compiler refers
to the computer to find out what a date looks like. A valid time can follow the
format hh:nn AM/PM or hh:nn:ss or one of the valid combinations. When
requesting a time from  the user, in case the user is not familiar with the rules
(and you should assume that the user doesn't know them), specify what
formula the user should follow. Here is an example:

C# 3.0 Practical Learning II 361


using System;

namespace DateAndTime
{
class Program
{
static int Main()
{
DateTime dateSubmitted;

Console.Write("Enter a date (yyyy/mm/dd): ");


dateSubmitted = DateTime.Parse(Console.ReadLine());

Console.WriteLine("\nDate Submitted: {0}\n",


dateSubmitted);
return 0;
}
}
}

Here is an example of running the program: 


Enter a date (yyyy/mm/dd): 1996/08/16

Date Submitted: 8/16/1996 12:00:00 AM

Press any key to continue . . .

The Characteristics of a Time Value


 

The Components of a Time

By now, we have seen that a time value is made of the hour, the minute, the
second, and the millisecond parts. These are values you can specify when
creating a time object using one of the appropriate constructors of the
DateTime structure. If you request a time value from the user or if the
application itself will provide it, you can retrieve its components.

To get the hour portion of an existing DateTime object, you can access its
Hour property. To retrieve the minute side of a time value, access its Minute
property. If you want to know the second value of a DateTime variable, you
can call its Second property. In the same way, you can get the millisecond
value of a time by accessing its Millisecond property.

The Time of Day of a DateTime Value

As seen so far, a DateTime variable always holds both a date and a time
portions. In your program, you may want to get only the time of the variable.
To support this, the DateTime structure is equipped with a property named

C# 3.0 Practical Learning II 362


TimeOfDay. This property produces the time value of an existing DateTime
object. Here is an example of using it:
using System;

namespace DateAndTime
{
class Program
{
static int Main()
{
DateTime time = new DateTime(2002, 4, 22, 16, 8,
44);

Console.WriteLine("Date and Time: {0}\n", time);


Console.WriteLine("Time of Day: {0}\n",
time.TimeOfDay);
return 0;
}
}
}

This would produce:


Date and Time: 4/22/2002 4:08:44 PM

Time of Day: 16:08:44

Press any key to continue . . .

Operations on Time Values


 

Converting a Time Value to a String

If you have a DateTime object, you can convert it to a String value. To


make this operation possible, the DateTime structure is equipped with a
method named ToString. The default version of this method takes no
argument and it simply creates a string out of a time value. Here is an
example:
using System;

namespace DateAndTime
{
class Program
{
static int Main()
{
DateTime time = new DateTime(2002, 4, 22, 16, 8,
44);
string strTime = time.ToString();

C# 3.0 Practical Learning II 363


Console.WriteLine("Date and Time(DateTime): {0}\n",
time);
Console.WriteLine("Date and Time(String): {0}\n",
strTime);
return 0;
}
}
}

This would produce:


Date and Time(DateTime): 4/22/2002 4:08:44 PM

Date and Time(String): 4/22/2002 4:08:44 PM

Press any key to continue . . .

Notice that the value produced by the string includes both the date, the time
and even the AM/PM section. In some cases, you would be interested only in
either the date or the time. To support this type of operation, the DateTime
structure has another overloaded version of the ToString() method that
takes as argument a String value. Its syntax is:
public string ToString(string format);

When calling this method, there are rules you should/must follow.

Time Rules and Formats

Like dates, time values follow the Regional (and Language) Settings of
Control Panel when they display. To make this display friendlier, Microsoft
Windows provides the rules, through some characters, you can use to format
a time:

C# 3.0 Practical Learning II 364


 The characters used to create a format are:

Format Used For Description

hh Hours An hour number from 0 to 23.


If the hour is less than 10, it would display with the leading 0
such as 08. Here is an example:
using System;

namespace DateAndTime
{
class Program
{
static int Main()
{
DateTime time = new DateTime(2002, 4,
22, 5, 8, 37);
string strHour = time.ToString("hh");

Console.WriteLine("Date and Time: {0}",


time);
Console.WriteLine("Hour Value:
{0}\n", strHour);

C# 3.0 Practical Learning II 365


return 0;
}
}
}

This would produce:


Date and Time: 4/22/2002 5:08:37 AM
Hour Value: 05

Press any key to continue . . .

If the hour is greater than 12, such as 15, 12 would be subtract


from it and it would display with a leading 0, such as 05. Here is
an example:
using System;

namespace DateAndTime
{
class Program
{
static int Main()
{
DateTime time = new DateTime(2002, 4,
22, 15, 8, 37);
string strHour = time.ToString("hh");

Console.WriteLine("Date and Time: {0}",


time);
Console.WriteLine("Hour Value:
{0}\n", strHour);
return 0;
}
}
}

This would produce:


Date and Time: 4/22/2002 5:08:37 AM
Hour Value: 05

Press any key to continue . . .


HH
Hours An hour number from 0 to 23.
If the hour is less than 10, it would display with the leading 0
such as 08. The effect is the same as seen for the hh format.
If the hour is greater than 12, such as 15, it would display with
that value. Here is an example:
using System;

namespace DateAndTime
{
class Program

C# 3.0 Practical Learning II 366


{
static int Main()
{
DateTime time = new DateTime(2002, 4,
22, 15, 8, 37);
string strHour = time.ToString("HH");

Console.WriteLine("Date and Time: {0}",


time);
Console.WriteLine("Hour Value:
{0}\n", strHour);
return 0;
}
}
}

This would produce:


Date and Time: 4/22/2002 3:08:37 PM
Hour Value: 15

Press any key to continue . . .


mm
Minutes A minute number from 0 to 59.
If the number is less than 10, it would display with the leading 0
such as 06. Here is an example:
using System;

namespace DateAndTime
{
class Program
{
static int Main()
{
DateTime time = new DateTime(2002, 4,
22, 15, 8, 37);
string strMinute = time.ToString("mm");

Console.WriteLine("Date and Time: {0}",


time);
Console.WriteLine("Minute Value:
{0}\n", strMinute);
return 0;
}
}
}

This would produce:


Date and Time: 4/22/2002 3:08:37 PM
Minute Value: 08

Press any key to continue . . .

C# 3.0 Practical Learning II 367


If the number is greater than 9, it would display the same.

ss Seconds A second value from 0 to 59.


If the number is less than 10, it would display with the leading 0
such as 04. Here is an example:
using System;

namespace DateAndTime
{
class Program
{
static int Main()
{
DateTime time = new DateTime(2002, 4,
22, 15, 8, 7);
string strSecond = time.ToString("ss");

Console.WriteLine("Date and Time: {0}",


time);
Console.WriteLine("Hour Value:
{0}\n", strSecond);
return 0;
}
}
}

This would produce:


Date and Time: 4/22/2002 3:08:07 PM
Hour Value: 07

Press any key to continue . . .

If the number is greater than 9, it would display like that. 

tt AM/PM Expression used to produce the AM or PM side of a time value.


or Here is an example:
tttt
using System;

namespace DateAndTime
{
class Program
{
static int Main()
{
DateTime time = new DateTime(2002, 4,
22, 5, 8, 7);
string strAMPM = time.ToString("tt");

Console.WriteLine("Date and Time: {0}",


time);

C# 3.0 Practical Learning II 368


Console.WriteLine("AM/PM Side:
{0}\n", strAMPM);
return 0;
}
}
}

This would produce:


Date and Time: 4/22/2002 5:08:07 AM
AM/PM Side: AM

Press any key to continue . . .

To create or format a (complete) time value, you must use a combination of


characters:

Format Used For Description

The character separator for time values.


This character is set in the Regional (and Language) Settings of
: Separator
Control Panel.
Don't use this character by itself in a ToString() method.

An hour number from 0 to 23.


If the hour is less than 10, it would display without the leading
h or H Hours
0.
Don't use the letter "h" or "H" by itself in a ToString() method

m
Minutes A minute number from 0 to 59.
If the number is less than 10, it would display without the
leading 0. Here is an example:
using System;

namespace DateAndTime
{
class Program
{
static int Main()
{
DateTime time = new DateTime(2002, 4,
22, 15, 8, 37);
string strMinute =
time.ToString("h:m");

Console.WriteLine("Date and Time: {0}",


time);
Console.WriteLine("Minute Value:
{0}\n", strMinute);

C# 3.0 Practical Learning II 369


return 0;
}
}
}

This would produce:


Date and Time: 4/22/2002 3:08:37 PM
Minute Value: 3:8

Press any key to continue . . .

If the minute number is greater than 9, it would display as such.


Don't use the letter "m" by itself in a ToString() method.
mm
Minutes A minute number from 0 to 59.
If the number is less than 10, it would display with a leading 0.
Here is an example:
using System;

namespace DateAndTime
{
class Program
{
static int Main()
{
DateTime time = new DateTime(2002, 4,
22, 15, 8, 37);
string strMinute =
time.ToString("h:mm");

Console.WriteLine("Date and Time: {0}",


time);
Console.WriteLine("Minute Value:
{0}\n", strMinute);
return 0;
}
}
}

This would produce:


Date and Time: 4/22/2002 3:08:37 PM
Minute Value: 3:08

Press any key to continue . . .

Don't pass "mm" by itself in a ToString() method


s
Seconds A second value from 0 to 59.
If the number is less than 10, it would display without a leading
0. Here is an example:

C# 3.0 Practical Learning II 370


using System;

namespace DateAndTime
{
class Program
{
static int Main()
{
DateTime time = new DateTime(2002, 4,
22, 15, 8, 7);
string strSecond =
time.ToString("h:mm:s");

Console.WriteLine("Date and Time: {0}",


time);
Console.WriteLine("Second Value:
{0}\n", strSecond);
return 0;
}
}
}

This would produce:


Date and Time: 4/22/2002 3:08:07 PM
Minute Value: 3:08:7

Press any key to continue . . .

Don't pass "mm" by itself in a ToString() method


ss
Seconds A second value from 0 to 59.
If the number is less than 10, it would display with a leading 0.
Here is an example:
using System;

namespace DateAndTime
{
class Program
{
static int Main()
{
DateTime time = new DateTime(2002, 4,
22, 15, 8, 7);
string strSecond =
time.ToString("h:mm:ss");

Console.WriteLine("Date and Time: {0}",


time);
Console.WriteLine("Second Value:
{0}\n", strSecond);
return 0;
}
}

C# 3.0 Practical Learning II 371


}

This would produce:


Date and Time: 4/22/2002 3:08:07 PM
Minute Value: 3:08:07

Press any key to continue . . .

Don't pass "mm" by itself in a ToString() method

When combining these characters to create a format, you should abide by the
rules of your language, such as US English. You should refer to the formula
set in the Time property page of the Regional (and Language) Settings of
Control Panel.

Comparison Operations On Time Values

As done for date values, you can compare time values to find out if one
occurs before another or whether they occur at the same time. To support
the comparisons, the DateTime structure is equipped with the Compare()
method.

Combining Date and Time


 

The Current Date and Time

When a user starts a computer and while using it, it keeps a date and time
values referred to as local date and time or system date and time. Depending
on your application, at one time you may need to get one or both of these
pieces of information. It is important to know that the computer, not you,
controls this information (but you can programmatically change it if you
want). To support both, the DateTime structure is equipped with a static
property named Now. This property holds the year, the month, the day, the
name of the day, the hour, the minute, and the second. Here is an example
of calling it:
using System;

namespace DateAndTime
{
class Program
{
static int Main()
{
Console.WriteLine("System Date and Time: {0}",
DateTime.Now);

C# 3.0 Practical Learning II 372


return 0;
}
}
}

Here is an example of running the program:


System Date and Time: 10/15/2006 3:08:48 PM
Press any key to continue . . .

To get the current date of the computer, the DateTime structure provides a
static property named Today. Here is an example:
using System;

namespace DateAndTime
{
class Program
{
static int Main()
{
Console.WriteLine("Current Date: {0}",
DateTime.Today);
return 0;
}
}
}

Here is an example of running the program:


Current Date: 10/15/2006 12:00:00 AM
Press any key to continue . . .

Formatting Date and Time Combinations

Although the DateTime structure is equipped to produce default values of a


date and time in combination, you can use the formats we have reviewed to
create your own date, in the sequences of your choice, such as a time
preceding a date, a value providing only the month and the minutes, etc.

C# 3.0 Practical Learning II 373


Windows Control: The Button
 

Description
On a typical application, a button is an object that the user clicks to perform
an action. To make this obvious, a button is a control surrounded by thick
borders. Here is an example of a button on a form:

Although a control is usually positioned on a form, there various other control


containers that can hold a button. These include the toolbar or the status bar,
and the other containers we have used so far.
To indicate what it is used for, a button displays some text as its caption. A
button can also display a picture instead. Another button can display both a string
and a picture. When you create a button, you will decide what it should display
and how it should behave.

Practical Learning: Introducing Buttons


1. Start Microsoft Visual C# and create a Windows Application named
Algebra2

2. On the main menu, click Project -> Add Class...

3. In the Templates list, make sure Class is selected.


Change the Name to Algebra and click Add

4. Change the file as follows:


 

C# 3.0 Practical Learning II 374


using System;

namespace Algebra2
{
public class Algebra
{
public static long Factorial(long x)
{
if (x <= 1)
return 1;
else
return x * Factorial(x - 1);
}

public static long Permutation(long n, long r)


{
if (r == 0)
return 0;
if (n == 0)
return 0;
if ((r >= 0) && (r <= n))
return Factorial(n) / Factorial(n - r);
else
return 0;
}

public static long Combinatorial(long a, long b)


{
if (a <= 1)
return 1;

return Factorial(a) / (Factorial(b) * Factorial(a -


b));
}
}
}

5. In the Solution Explorer, right-click Form1.cs and click Rename

6. Type Exercise.cs and press Enter twice (to save and to open the form)

7. Click the body of the form to make sure it is selected.


In the Properties window, change the following characteristics
FormBorderStyle: FixedDialog
Text: Factorial, Permutation, and Combination
Size: 304, 208
StartPosition: CenterScreen
MaximizeBox: False
MinimizeBox: False

8. In the Containers section of the Toolbox, click TabControl and click the
form

9. On the form, right-click the right side of tabPage2 and click Add Page

C# 3.0 Practical Learning II 375


10. Based on what we learned in Lesson 24, design the form as follows:
 

Control Text Name Additional Properties

HotTrack: True
TabControl   tclAlgebra Location: 12, 12
Size: 304, 235

TabPage Factorial tabFactorial  

Label Number:   Location: 22, 21

TextAlign: Right
TextBox   txtNumber Location: 88, 18
Size: 50, 20

Label Result:   Location: 22, 56

TextAlign: Right
TextBox   txtFactorial Location: 88, 54
Size: 140, 20

C# 3.0 Practical Learning II 376


Control Text Name Location Size

TabPage Permutation tabPermutation    

Label n:   22, 21  

TextBox   txtPermutationN 88, 18 50, 20

Label r:   22, 56  

TextBox   txtPermutationR 88, 54 50, 20

Label P(n, r):   22, 92  

TextBox   txtPermutation 88, 90 140, 20

C# 3.0 Practical Learning II 377


Control Text Name Location Size

TabPage Combination tabCombination    

Label n:   22, 21  

TextBox   txtCombinationN 88, 18 50, 20

Label r:   22, 56  

TextBox   txtCombinationR 88, 54 50, 20

Label C(n, r):   22, 92  

TextBox   txtCombination 88, 90 140, 20

11. Save the form

Creating a Button
To support the buttons of an application, the .NET Framework provides an
abstract class named ButtonBase. The regular button of Microsoft Windows
is implemented by the Button class. At design time, to add a button to your
project, from the Common Controls section of the Toolbox, you can click the
Button and click the form or another container.

To programmatically create a button, you can declare a variable of type


Button and use the new operator to allocate memory for it. Here is an
example:
using System;
using System.Drawing;
using System.Windows.Forms;

public class Exercise : System.Windows.Forms.Form


{
Button btnResume;

public Exercise()
{
InitializeComponent();
}

C# 3.0 Practical Learning II 378


private void InitializeComponent()
{
btnResume = new Button();
btnResume.Location = new Point(32, 20);

this.Controls.Add(btnResume);
}
}

public class Program


{
static int Main()
{
System.Windows.Forms.Application.Run(new Exercise());
return 0;
}
}

Practical Learning: Creating Buttons

1. In the combo box on top of the Properties window, select tabFactorial

2. From the Common Controls section of the Toolbox, click Button and click
on the right side of the top text box

C# 3.0 Practical Learning II 379


The Characteristics of a Button
 

The Caption of a Button


For a user, the most important aspects of a button are the message it
displays and the action it performs. The text the button displays allows the
user to know what the button is used for. This is represented by the Text
property. The most popular strings that the buttons display are OK and
Cancel. The OK caption is set for a form or a dialog box that informs the user
of an error, an intermediary situation, or an acknowledgement of an action
that was performed on the dialog that hosts the button. The Cancel caption is
useful on a button whose main parent (the form or the dialog box) would ask
a question or request a follow-up action from the user. Whenever a dialog
box allows the user to dismiss it without continuing the action, you should
provide a button with a Cancel caption.

After adding a button to a form (by design or with code), you can change its
caption with code by assigning the desired string to the Text property. For
example, you can change the caption of a button as follows:
button1.Text = "Let it Go!";

After specifying the Text of a button, by default, it's positioned in the middle
center of the button:

The position of the text of a button is controlled through the TextAlign


property which is a value of the ContentAlignment enumerator. The possible
values are:

TopLeft TopCenter TopRight

MiddleLeft MiddleCenter MiddleRight

BottomLeft BottomCenter BottomRight

C# 3.0 Practical Learning II 380


Here is an example:
public class Exercise : System.Windows.Forms.Form
{
Button btnResume;

public Exercise()
{
InitializeComponent();
}

private void InitializeComponent()


{
btnResume = new Button();
btnResume.Text = "Resume";
btnResume.Location = new Point(32, 20);
btnResume.Size = new System.Drawing.Size(120, 48);
btnResume.TextAlign = ContentAlignment.BottomCenter;

Controls.Add(btnResume);
}
}

Practical Learning: Using the Buttons


1. Access each tab page and add a button to it

2. Add a button to the form and under the tab control

3. Complete the design of the form as follows:


 

C# 3.0 Practical Learning II 381


Control Text Name

Button Calculate btnCalcFactorial

Button Close btnClose

Control Text Name

Button Calculate btnCalcPermutation

C# 3.0 Practical Learning II 382


Control Text Name

Button Calculate btnCalcCombination

4. Access the Factorial tab page and double-click its Calculate button

5. Implement the event as follows:


 
private void btnCalcFactorial_Click(object sender, EventArgs e)
{
long number = 0;
long result;

try
{
number = long.Parse(txtFactNumber.Text);
result = Algebra.Factorial(number);
txtFactorial.Text = result.ToString();
}
catch (FormatException)
{
MessageBox.Show("Invalid Number");
}
}

6. Return to the form

7. Access the Permutation tab page and double-click its Calculate button

8. Implement the event as follows:


 
private void btnCalcPermutation_Click(object sender, EventArgs
e)
{

C# 3.0 Practical Learning II 383


long n = 0, r = 0;
long result;

try
{
n = long.Parse(txtPermutationN.Text);
}
catch (FormatException)
{
MessageBox.Show("Invalid Number");
}

try
{
r = long.Parse(txtPermutationR.Text);
result = Algebra.Permutation(n, r);
txtPermutation.Text = result.ToString();
}
catch (FormatException)
{
MessageBox.Show("Invalid Number");
}
}

9. Return to the form

10. Access the Combination tab page and double-click its Calculate button

11. Implement the event as follows:


 
private void btnCalcCombination_Click(object sender, EventArgs
e)
{
long n = 0, r = 0;
long result;

try
{
n = long.Parse(txtCombinationN.Text);
}
catch (FormatException)
{
MessageBox.Show("Invalid Number");
}

try
{
r = long.Parse(txtCombinationR.Text);
result = Algebra.Combinatorial(n, r);
txtCombination.Text = result.ToString();
}
catch (FormatException)
{
MessageBox.Show("Invalid Number");
}

C# 3.0 Practical Learning II 384


}

12. Return to the form and double-click the Close button

13. Implement the event as follows:


 
private void btnClose_Click(object sender, EventArgs e)
{
Close();
}

14. Execute the application to test the calculations


 

C# 3.0 Practical Learning II 385


15. Close the form and return to your programming environment

The Image on a Button


Besides, or instead, of a caption, a button can display a picture on top. If you
want a button to display a bitmap, you should first create, design, or have a
picture. Then, in the Properties window, use the Image field to select a
bitmap or an icon. You can also programmatically assign an Image object to
the Image property. Here is an example:
private void InitializeComponent()
{
btnResume = new Button();
btnResume.Text = "Resume";
btnResume.Location = new Point(32, 20);
btnResume.Size = new System.Drawing.Size(120, 48);
btnResume.Image =
Image.FromFile(@"E:\Programs\neutral.gif");

Controls.Add(btnResume);
}

This would produce:

By default, both the caption and the image display ion the middle-center of
the button. To make them distinct and allow the user to see both, you can
design a bitmap that has both and assign that bitmap as the image of the
button. Alternatively, you can use a separate string and a separate picture.

C# 3.0 Practical Learning II 386


Fortunately, each can have its own alignment. We already saw how to control
the alignment of the caption.

Besides displaying an image, the Button class is equipped with the


ImageAlign property that allows you to specify the alignment of the image.
The ImageAlign property is inherited from the ButtonBase class. The
ButtonBase.ImageAlign property is based on the ContentAlignment
enumeration that we are already familiar with. Here is an example:
private void InitializeComponent()
{
btnResume = new Button();
btnResume.Location = new Point(32, 20);
btnResume.Size = new System.Drawing.Size(120, 48);
btnResume.Text = "Resume";
btnResume.TextAlign = ContentAlignment.BottomCenter;
btnResume.Image =
Image.FromFile(@"E:\Programs\neutral.gif");
btnResume.ImageAlign = ContentAlignment.TopCenter;

Controls.Add(btnResume);
}

This would produce:

Instead of using the Image property, you can first create an image list and
add some pictures to it. Then, using the ImageList property, assign it to the
button. Use the ImageIndex property to specify what picture would be displayed
on the button.

The Flat Style of a Button


A regular button displays with raised borders as originally set by the operating
system. To give your button a fancy look and behavior, you can use the
FlatStyle property. The FlatStyle property is based on an enumeration of
the same name. It provides 4 values that are:

 Flat: The button appears flat. When the mouse is over it, it becomes
highlighted

 Popup: The button appears flat. When the mouse is over it, the borders
of the button are raised

C# 3.0 Practical Learning II 387


 Standard: The button appears and behave like all regular buttons you
have seen

 System: The appearance of the button depends on the operating system

Obviously the most important and the most intuitive event of a button occurs
when clicked. This event is of type EventArgs, which indicates that it doesn't
provide nor does it need any formal details about what is going on. To launch
this event, you can double-click the button on the form. To create this event
programmatically, first implement the method that would carry its
assignment, then increment-add (with the += operator) it to the Click
property of the button by assigning it the EventHandler constructor.

The Result of a Dialog Box


After the user has used a form or dialog box, to close it, the user would click
a button. When the user does this, you must find out what button was
clicked. Although there are various ways you can get this information, to
assist you, the .NET Framework provides a convenient mechanism through an
enumeration named DialogResult.

When creating a form or a dialog box, after adding a button, in the Properties
window, click DialogResult and select on the values:

Except for None, by default, it does not matter what value you select but, you
should follow Windows standard to select the right value.

After specifying the returned value of a button, access the properties of the
form or dialog box:

 If you had selected OK as the DialogResult value of a button, you


should select the name of that button for the AcceptButton property of
the form

C# 3.0 Practical Learning II 388


 If you had selected Cancel as the DialogResult value of a button, you
should select the name of that button for the CancelButton property of
the form

After configuring the DialogResult of the button(s), when the user clicks
one of the buttons to close the form or dialog box, you can get the value of
the Form.ShowDialog() method which returns one of the values of the
DialogResult enumeration.

Applications:
Algebra

Simple Interest

C# 3.0 Practical Learning II 389


Windows Control: The Combo Box
 

Description
A combo box is a list of items that the user can select from. Like a list box, a
combo box is usually made of a list of strings. Unlike a list box, a combo box
saves space by using just as much room as a text box control. To show that it
is holding a list, a combo box displays a down-pointing arrow on the right side
of its text box. In the following screenshot, the Font Effects property page of
the Character dialog box of OpenOffice.org presents the Underlining, the
Color, the Effects, the Strikethrough, the Relief, and the Font Color combo
boxes:

Because a combo box does not (permanently) display its list like a list box, to
show its content, the user can click the arrow button. Here is an example:

C# 3.0 Practical Learning II 390


Creating a Combo Box
To support combo boxes, the .NET Framework provides a class named
ComboBox. At design time, to add a combo box to your application, from the
Common Controls section of the Toolbox, you can click the ComboBox button
and click the form or a container. Like ListBox, the ComboBox class is
derived from the ListControl class. Therefore, to programmatically create a
combo box, declare a variable of type ComboBox, allocate its memory with the
new operator and add it to the Controls collection of its container. Here is
an example:
using System;
using System.Drawing;
using System.Windows.Forms;

public class Exercise : System.Windows.Forms.Form


{
Label lblTitle;
ComboBox cbxAcademicDisciplines;

public Exercise()
{
InitializeComponent();
}

private void InitializeComponent()


{
lblTitle = new Label();

C# 3.0 Practical Learning II 391


lblTitle.Text = "Academic Disciplines";
lblTitle.Location = new Point(12, 12);
lblTitle.AutoSize = true;
Controls.Add(lblTitle);

cbxAcademicDisciplines = new ComboBox();


cbxAcademicDisciplines.Location = new Point(12, 32);

Controls.Add(cbxAcademicDisciplines);
}
}

public class Program


{
static int Main()
{
System.Windows.Forms.Application.Run(new Exercise());
return 0;
}
}

This would produce:

Practical Learning: Introducing Combo Boxes

1. Start Microsoft Visual C# and create a new Windows Application named


CollegeParkAutoParts1

2. In the Solution Explorer, right-click Form1.cs and click Rename

3. Type Central.cs and press Enter

4. Design the form as follows:


 

C# 3.0 Practical Learning II 392


Control Text Name Other Properties

GroupBox Parts Selection    

Font: Microsoft
Label Year   Sans Serif, 8.25pt,
style=Bold

Microsoft Sans
Label Make   Serif, 8.25pt,
style=Bold

Microsoft Sans
Label Model   Serif, 8.25pt,
style=Bold

C# 3.0 Practical Learning II 393


Microsoft Sans
Label Category   Serif, 8.25pt,
style=Bold

ComboBox   cbxCarYears  

ComboBox   cbxMakes  

ComboBox   cbxModels  

ComboBox   cbxCategories  

Font: Microsoft
Label Available Parts   Sans Serif, 9.75pt,
style=Bold

ListBox   lbxPartNumbers  

ListBox   lbxPartNames  

ListBox   lbxUnitPrices  

Customer
GroupBox Selected    
Items

Label Part #    

Label Part Name    

Label Unit Price    

C# 3.0 Practical Learning II 394


Label Qty    

Label Sub Total    

TextBox   txtPartNumber1  

TextBox   txtPartName1  

TextBox 0.00 txtUnitPrice1 TextAlign: Right

TextBox 0 txtQuantity1 TextAlign: Right

TextBox 0.00 txtSubTotal1 TextAlign: Right

Button Remove btnRemove1  

TextBox   txtPartNumber2  

TextBox   txtPartName2  

TextBox 0.00 txtUnitPrice2 TextAlign: Right

TextBox 0 txtQuantity2 TextAlign: Right

TextBox 0.00 txtSubTotal2 TextAlign: Right

Button Remove btnRemove2  

TextBox   txtPartNumber3  

C# 3.0 Practical Learning II 395


TextBox   txtPartName3  

TextBox 0.00 txtUnitPrice3 TextAlign: Right

TextBox 0 txtQuantity3 TextAlign: Right

TextBox 0.00 txtSubTotal3 TextAlign: Right

Button Remove btnRemove3  

TextBox   txtPartNumber4  

TextBox   txtPartName4  

TextBox 0.00 txtUnitPrice4 TextAlign: Right

TextBox 0 txtQuantity4 TextAlign: Right

TextBox 0.00 txtSubTotal4 TextAlign: Right

Button Remove btnRemove4  

TextBox   txtPartNumber5  

TextBox   txtPartName5  

TextBox 0.00 txtUnitPrice5 TextAlign: Right

TextBox 0 txtQuantity5 TextAlign: Right

C# 3.0 Practical Learning II 396


TextBox 0.00 txtSubTotal5 TextAlign: Right

Button Remove btnRemove5  

TextBox   txtPartNumber6  

TextBox   txtPartName6  

TextBox 0.00 txtUnitPrice6 TextAlign: Right

TextBox 0 txtQuantity6 TextAlign: Right

TextBox 0.00 txtSubTotal6 TextAlign: Right

Button Remove btnRemove6  

Label Total Order    

TextBox 0.00 txtTotalOrder  

Button Close btnClose  

5. Execute the application to test it

6. Close the form and return to your programming environment

C# 3.0 Practical Learning II 397


The Combo Box: Creating and
Selecting Items
 

 
Introduction

Like all visual controls, a combo box shares all the basic characteristics of
other graphic control: the name, the location, the size, the ability to be
enabled or disabled, the ability to hide or show it, the ability to dock or
anchor, etc.

Creating the List of Items


Probably the most important aspect of a combo box is the list of items it
holds. Like the list box and all other list-based controls, the list of a combo
box is held by the Items property. You create this list using the exact same
techniques we reviewed for the list box. This means that you can use the
String Collection Editor.

The Items property of the ComboBox class is created from the nested
ObjectCollection class. This class has the same functionality and features
as its counterpart of the list box. This means that, to programmatically create
of items, you can (continuously) call the ObjectCollection.Add() method.
Here is an example:
public class Exercise : System.Windows.Forms.Form
{
Label lblTitle;
ComboBox cbxAcademicDisciplines;

public Exercise()
{
InitializeComponent();
}

private void InitializeComponent()


{
lblTitle = new Label();
lblTitle.Text = "Academic Disciplines";
lblTitle.Location = new Point(12, 12);
lblTitle.AutoSize = true;
Controls.Add(lblTitle);

C# 3.0 Practical Learning II 398


cbxAcademicDisciplines = new ComboBox();
cbxAcademicDisciplines.Location = new Point(12, 32);
cbxAcademicDisciplines.Items.Add("Natural sciences");
cbxAcademicDisciplines.Items.Add("Mathematics and
Computer sciences");
cbxAcademicDisciplines.Items.Add("Social sciences");
cbxAcademicDisciplines.Items.Add("Humanities");
cbxAcademicDisciplines.Items.Add("Professions and
Applied sciences");

Controls.Add(cbxAcademicDisciplines);
}
}

This would produce:

To add an array of items, you can call the AddRange() method. To insert an
item somewhere inside the list, you can call the Insert() method.

If you want the list of items to be sorted, you can change the value of the
Sorted property in the Properties window from False (the default) to True.
To sort a list programmatically, you can assign a true value to the Sorted
property. You can un-sort the list by changing the value of the Sorted
property. This property works exactly like its equivalent in the ListBox control.

Practical Learning: Using the ObjectCollection Class

1. To create a list of items using the Add() method, double-click an unoccupied


area of the form and implement its Load event as follows:
 
private void Central_Load(object sender,
EventArgs e)
{
for (int i = DateTime.Now.Year; i
>= 1960; i--)

this.cbxCarYears.Items.Add(i);
}

2. Save the form

C# 3.0 Practical Learning II 399


Selecting an Item
To select an item from the list, the user can click it. To programmatically
select an item, you can assign a string to the Text property of a DropDown or
a Simple combo box. Probably the best way to select an item is to specify its
index. The items of a combo box are stored in a zero-based list. To select an
item, you can assign its position to the SelectedIndex property. In the same
way, to find out what item is selected, you can get the value of the
SelectedIndex property.

Instead of using of using the index of an item, to select an item using its
identity or name, you can use the SelectedItem property. To select an item
by its name, assign it to the SelectedItem property.

Practical Learning: Using the ObjectCollection Class

1. On the main menu, click Project -> Add Class...

2. Set the name to PartDescription and press Enter

3. To create a class that can holds a structured item of a list, change the
class as follows:
 
using System;

namespace CollegeParkAutoParts1
{
public class PartDescription
{
private long ID;
private int yr;
private string mk;
private string mdl;
private string cat;
private string name;
private decimal price;

public PartDescription()
{
this.ID = 0;
this.yr = 1960;
this.mk = "";
this.mdl = "";
this.name = "Unknown";
this.price = 0.00M;
}

public PartDescription(long code, int year, string make,


string model, string type,
string desc, decimal UPrice)
{

C# 3.0 Practical Learning II 400


this.ID = code ;
this.yr = year;
this.mk = make;
this.mdl = model;
this.cat = type;
this.name = desc;
this.price = UPrice;
}

public long PartNumber


{
get { return ID; }
set { ID = value; }
}

public int CarYear


{
get { return yr; }
set { yr = value; }
}

public string Make


{
get { return mk; }
set { mk = value; }
}

public string Model


{
get { return mdl; }
set { mdl = value; }
}

public string Category


{
get { return cat ; }
set { cat = value; }
}

public string PartName


{
get { return name; }
set { name = value; }
}

public decimal UnitPrice


{
get { return (price < 0) ? 0.00M : price; }
set { price = value; }
}

public override string ToString()


{
return this.PartNumber + " " +
this.CarYear.ToString() + " " +
this.Make + " " +

C# 3.0 Practical Learning II 401


this.Model + " " +
this.Category + " " +
this.PartName + " " +
this.UnitPrice;
}
}
}

4. Access the Central.cs code file and change it as follows:


 
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace CollegeParkAutoParts1
{
public partial class Central : Form
{
PartDescription[] parts = new PartDescription[56];

public Central()
{
InitializeComponent();
}

private void Central_Load(object sender, EventArgs e)


{
for (int i = DateTime.Now.Year; i >= 1960; i--)
this.cbxCarYears.Items.Add(i);

parts[0] = new PartDescription(447093, 2002, "Ford",


"Escort SE L4 2.0", "Engine Electrical",
"Alternator 75amp Remanufactured; w/ 75 Amp",
205.05M);
parts[1] = new PartDescription(203815, 2006,
"Dodge",
"Caravan SE L4 2.4", "Cooling System",
"Radiator Cap", 6.65M);
parts[2] = new PartDescription(293047, 2000,
"Toyota",
"RAV4 2WD/4-DOOR", "Cooling System",
"Thermostat Gasket", 4.95M);
parts[3] = new PartDescription(990468, 2002,
"Honda",
"Civic 1.7 EX 4DR", "Exhaust",
"Bolt & Spring Kit (Manifold outlet, Muffler
Inlet)",
85.75M);
parts[4] = new PartDescription(304158, 1996,
"Buick",
"Regal Custom V6 3.8", "Fuel Injection",

C# 3.0 Practical Learning II 402


"Fuel Injector", 82.75M);
parts[5] = new PartDescription(807245, 2004,
"Acura",
"MDX 3.5 4WD", "Driveshaft & Axle",
"CV Boot Clamp 7 x 750mm; 1 Large + 1 Small
Clamp",
1.60M);
parts[6] = new PartDescription(203485, 2001, "Ford",
"Taurus LX V6 3.0", "Fuel Injection",
"Oxygen Sensor OE Style 4Wire; Front; 2
Required",
52.65M);
parts[7] = new PartDescription(248759, 1999, "Jeep",
"Wrangler Sahara", "Air Intake",
"Air Filter AirSoft Panel", 7.95M);
parts[8] = new PartDescription(202848, 1998,
"Honda",
"Accord 2.3 LX 4DR", "Air Intake",
"Air Filter", 12.55M);
parts[10] = new PartDescription(932759, 2006, "Kia",
"Rio 1.6DOHC16V 4-DR", "Cooling System",
"Thermostat", 14.45M);
parts[11] = new PartDescription(304975, 2000,
"Honda",
"Civic 1.6 EX 4DR", "Suspension",
"Ball Joint; Front Lower; 2 per car", 40.55M);
parts[12] = new PartDescription(208450, 2003,
"Chevrolet",
"Monte Carlo LS V6 3.4", "Fuel Injection",
"Oxygen Sensor OE connector; Rear", 65.55M);
parts[13] = new PartDescription(209480, 2002,
"Ford",
"Focus SE DOHC L4 2.0", "Steering",
"Steering Rack Remanufactured", 170.85M);
parts[9] = new PartDescription(203495, 2004,
"Honda",
"Civic 1.7 EX 4DR", "Climate Control",
"A/C Clutch; OE compressor = Sanden", 184.95M);
parts[14] = new PartDescription(203480, 2007,
"Toyota",
"Corolla", "Air Intake",
"Air Filter", 12.65M);
parts[15] = new PartDescription(109379, 2005,
"Volvo",
"S40 2.5L T5 AWD", "Fuel Delivery",
"Fuel Filter; Early Design; Outer Diameter =
55mm",
30.95M);
parts[16] = new PartDescription(935794, 2002,
"Ford",
"Escape XLS 4WD", "Brake",
"Brake Caliper Remanufactured; Front Right",
65.55M);
parts[17] = new PartDescription(203485, 2006, "BMW",
"325i", "Climate Control",
"AC High Pressure Side Switch",

C# 3.0 Practical Learning II 403


49.95M);
parts[18] = new PartDescription(204875, 1996,
"Chevrolet",
"Monte Carlo Z34 V6 3.4", "Fuel Delivery",
"Fuel Filter", 8.05M);
parts[19] = new PartDescription(937485, 2007,
"Toyota",
"Camry V6", "Air Intake", "Air Filter", 12.95M);
parts[20] = new PartDescription(294759, 2001,
"Ford",
"Escape XLT 4WD", "Air Intake",
"Air Filter Panel", 7.25M);
parts[21] = new PartDescription(297495, 2003,
"Honda",
"Civic 1.7 EX 4DR", "Brake",
"Brake Caliper Reman; w/ ProAct Pads; Front
Right",
82.55M);
parts[22] = new PartDescription(794735, 2006, "BMW",
"325i", "Climate Control",
"Cabin Air/Pollen Filter; With Activated
Carbon",
28.05M);
parts[23] = new PartDescription(937485, 2007,
"Toyota",
"Corolla", "Body Electrical",
"Halogen SilverStar; 12V 65W; inner-high beam",
22.85M);
parts[24] = new PartDescription(492745, 2005,
"Ford",
"Focus ZX3 L4 2.0", "Air Intake",
"Fuel Injection Perf Kit", 342.95M);
parts[25] = new PartDescription(937005, 2004,
"Acura",
"MDX 3.5 4WD", "Driveshaft & Axle",
"CV Boot Clamp 7 x 750mm; For Large End of Boot;
inner boot",
1.60M);
parts[26] = new PartDescription(293749, 2004,
"Acura",
"MDX 3.5 4WD", "Driveshaft & Axle",
"Axle Nut 24mm x 1;5; rear ",
2.35M);
parts[27] = new PartDescription(920495, 2006, "BMW",
"325i", "Climate Control",
"Adjustable Telescoping Mirror", 7.95M);
parts[28] = new PartDescription(204075, 2004,
"Acura",
"MDX 3.5 4WD", "Driveshaft & Axle",
"Wheel Bearing; Rear; 1 per wheel",
70.15M);
parts[29] = new PartDescription(979304, 2000,
"Toyota",
"RAV4 2WD/4-DOOR", "Cooling System",
"Thermostat Housing", 20.95M);

C# 3.0 Practical Learning II 404


parts[30] = new PartDescription(300456, 2004,
"Acura",
"MDX 3.5 4WD", "Driveshaft & Axle",
"Wheel Bearing; Front; 1 per wheel",
66.65M);
parts[31] = new PartDescription(404860, 2001,
"Ford",
"Taurus LX V6 3.0", "Suspension",
"Shock Absorber GR2; Rear; Wagon only",
39.40M);
parts[32] = new PartDescription(585688, 2007,
"Buick",
"Lacrosse CXS V6 3.6", "Brake",
"Climate Control", 10.65M);
parts[33] = new PartDescription(739759, 2001,
"Ford",
"Taurus LX V6 3.0", "Suspension",
"Shock Absorber GasaJust; Rear; Wagon only",
30.95M);
parts[34] = new PartDescription(927495, 2005,
"Volvo",
"S40 2.5L T5 AWD", "Engine Mechanical",
"Timing Belt Idler Pulley Original Equipment
INA",
65.55M);
parts[40] = new PartDescription(979374, 2000,
"Toyota",
"RAV4 2WD/4-DOOR", "Cooling System",
"Thermostat Gasket", 4.95M);
parts[35] = new PartDescription(542347, 2007,
"Buick",
"Lacrosse CXS V6 3.6", "Brake",
"Brake Pad Set ProACT Ceramic w/Shims; Front",
80.05M);
parts[36] = new PartDescription(683064, 2000,
"Toyota",
"RAV4 2WD/4-DOOR", "Cooling System",
"Radiator Hose; Upper", 103.75M);
parts[37] = new PartDescription(248759, 1999,
"Jeep",
"Wrangler Sahara", "Air Intake",
"Air Filter", 50.95M);
parts[38] = new PartDescription(973974, 2007,
"Toyota",
"Corolla", "Air Intake",
"Air Mass Meter; W/o Housing; Meter/sensor
only",
134.95M);
parts[39] = new PartDescription(285800, 2001,
"Ford",
"Escape XLT 4WD", "Transmission",
"AT Filter", 34.95M);
parts[41] = new PartDescription(207495, 2007,
"Toyota",
"Corolla", "Body Electrical",

C# 3.0 Practical Learning II 405


"Headlight Bulb; 12V 65W; inner-high beam",
9.35M);
parts[42] = new PartDescription(566676, 2000,
"Toyota",
"RAV4 2WD/4-DOOR", "Cooling System",
"Auxiliary Fan Switch", 42.95M);
parts[43] = new PartDescription(304950, 2007,
"Toyota",
"Corolla", "Body Electrical",
"Headlight Bulb; 12V 51W; outer", 7.85M);
parts[44] = new PartDescription(797394, 2000,
"Toyota",
"RAV4 2WD/4-DOOR", "Cooling System",
"Water Flange Gasket", 0.85M);
parts[45] = new PartDescription(910203, 2007,
"Buick",
"Lacrosse CXS V6 3.6", "Suspension",
"Strut Mount Inc; Sleeve; Rear Right", 80.85M);
parts[46] = new PartDescription(790794, 2000,
"Toyota",
"RAV4 2WD/4-DOOR", "Cooling System",
"Radiator Hose; Lower", 9.45M);
parts[47] = new PartDescription(970394, 2007,
"Buick",
"Lacrosse CXS V6 3.6", "Suspension",
"Coil Spring Insulator; Front Lower",
14.55M);
parts[48] = new PartDescription(290840, 2005,
"Volvo",
"S40 2.5L T5 AWD", "Engine Mechanical",
"Rod Bearing Set 1 per Rod; Standard; Reqs. 5-
per Engine",
26.95M);
parts[49] = new PartDescription(209704, 2007,
"Toyota",
"Corolla", "Body Electrical",
"Wiper Blade Excel+; Front Right", 7.25M);
parts[50] = new PartDescription(200368, 2000,
"Toyota",
"RAV4 2WD/4-DOOR", "Cooling System",
"Radiator Drain Plug incl; gasket", 3.15M);
parts[51] = new PartDescription(200970, 2005,
"Volvo",
"S40 2.5L T5 AWD", "Engine Mechanical",
"Reference Sensor; Flywheel Engine Speed",
62.05M);
parts[52] = new PartDescription(542347, 2007,
"Buick",
"Lacrosse CXS V6 3.6", "Air Intake",
"Air Filter", 50.25M);
parts[53] = new PartDescription(927045, 2001,
"Ford",
"Escape XLT 4WD", "Air Intake",
"Air Filter", 62.95M);
parts[54] = new PartDescription(990659, 2000,
"Toyota",

C# 3.0 Practical Learning II 406


"RAV4 2WD/4-DOOR", "Cooling System",
"Radiator OE Plastic tank", 136.85M);
parts[55] = new PartDescription(440574, 2007,
"Buick",
"Lacrosse CXS V6 3.6", "Suspension",
"Strut Mount Inc; Sleeve; Rear Left",
80.80M);
}
}
}

5. Return to the form and double-click the Year combo box

6. To display the list of car makes when the user selects a year, implement
the event as follows:
 
private void cbxCarYears_SelectedIndexChanged(object sender,
EventArgs e)
{
cbxMakes.Text = "";
cbxMakes.Items.Clear();
cbxModels.Text = "";
cbxModels.Items.Clear();
cbxCategories.Text = "";
cbxCategories.Items.Clear();

lbxPartNumbers.Items.Clear();
lbxPartNames.Items.Clear();
lbxUnitPrices.Items.Clear();

foreach (PartDescription part in parts)


if (part.CarYear == int.Parse(cbxCarYears.Text))
if( cbxMakes.FindString(part.Make) == -1 )
cbxMakes.Items.Add(part.Make);
}

7. Return to the form and double-click the Make combo box

8. To display the list of car models when the user has selected a year and a
make, implement the event as follows:
 
private void cbxMakes_SelectedIndexChanged(object sender,
EventArgs e)
{
cbxModels.Text = "";
cbxModels.Items.Clear();
cbxCategories.Text = "";
cbxCategories.Items.Clear();

lbxPartNumbers.Items.Clear();
lbxPartNames.Items.Clear();
lbxUnitPrices.Items.Clear();

foreach (PartDescription part in parts)

C# 3.0 Practical Learning II 407


if( (part.CarYear ==
int.Parse(cbxCarYears.Text)) &&
(part.Make == cbxMakes.Text) )
if (cbxModels.FindString(part.Model) == -1)
cbxModels.Items.Add(part.Model);
}

9. Return to the form and double-click the Model combo box

10. To display the list of categories after the user has selected the year, the
make, and the model, implement the event as follows:
 
private void cbxModels_SelectedIndexChanged(object sender,
EventArgs e)
{
lbxPartNumbers.Items.Clear();
lbxPartNames.Items.Clear();
lbxUnitPrices.Items.Clear();

foreach (PartDescription part in parts)


if ((part.CarYear ==
int.Parse(cbxCarYears.Text)) &&
(part.Make == cbxMakes.Text) &&
(part.Model == cbxModels.Text) )
if (cbxCategories.FindString(part.Category)
== -1)
cbxCategories.Items.Add(part.Category);
}

11. Return to the form and double-click the Category combo box

12. To display the list of available parts, implement the event and define a
new method  as follows:
 
private void cbxCategories_SelectedIndexChanged(object sender,
EventArgs e)
{
lbxPartNumbers.Items.Clear();
lbxPartNames.Items.Clear();
lbxUnitPrices.Items.Clear();

foreach (PartDescription part in parts)


if ((part.CarYear == int.Parse(cbxCarYears.Text)) &&
(part.Make == cbxMakes.Text) &&
(part.Model == cbxModels.Text) &&
(part.Category == cbxCategories.Text))
{

lbxPartNumbers.Items.Add(part.PartNumber.ToString());
lbxPartNames.Items.Add(part.PartName);

lbxUnitPrices.Items.Add(part.UnitPrice.ToString());
}
}

C# 3.0 Practical Learning II 408


13. Return to the form and double-click the lbxPartNumbers list box

14. When the user clicks an item from the Part Numbers list box, to make
sure the corresponding item is selected in the other list boxes,
implement the event as follows:
 
private void lbxPartNumbers_SelectedIndexChanged(object sender,
EventArgs e)
{
lbxUnitPrices.SelectedIndex =
lbxPartNames.SelectedIndex =
lbxPartNumbers.SelectedIndex;
}

15. Return to the form and double-click the lbxPartNames list box

16. Implement the event as follows:


 
private void lbxPartNames_SelectedIndexChanged(object sender,
EventArgs e)
{
lbxPartNumbers.SelectedIndex =
lbxUnitPrices.SelectedIndex =
lbxPartNames.SelectedIndex;
}

17. Return to the form and double-click the lbxUnitPrices list box

18. Implement the event as follows:


 
private void lbxUnitPrices_SelectedIndexChanged(object sender,
EventArgs e)
{
lbxPartNames.SelectedIndex =
lbxPartNumbers.SelectedIndex =
lbxUnitPrices.SelectedIndex;
}

19. Return to the form and click (once) the lbxPartNumbers list combo box

20. In the Properties window, click the Events button and, in the Events
section, double-click DoubleClick

21. Implement the event as follows:


 
internal void CalculateOrder()
{
// Calculate the current total order and update the
order
decimal subTotal1 = 0.00M, subTotal2 = 0.00M, subTotal3
= 0.00M,

C# 3.0 Practical Learning II 409


subTotal4 = 0.00M, subTotal5 = 0.00M,
subTotal6 = 0.00M;
decimal orderTotal = 0.00M;

// Retrieve the value of each sub total


try
{
subTotal1 =
decimal.Parse(this.txtSubTotal1.Text);
}
catch (FormatException)
{
MessageBox.Show("Invalid Value");
}

try
{
subTotal2 =
decimal.Parse(this.txtSubTotal2.Text);
}
catch (FormatException)
{
MessageBox.Show("Invalid Value");
}

try
{
subTotal3 =
decimal.Parse(this.txtSubTotal3.Text);
}
catch (FormatException)
{
MessageBox.Show("Invalid Value");
}

try
{
subTotal4 =
decimal.Parse(this.txtSubTotal4.Text);
}
catch (FormatException)
{
MessageBox.Show("Invalid Value");
}

try
{
subTotal5 =
decimal.Parse(this.txtSubTotal5.Text);
}
catch (FormatException)
{
MessageBox.Show("Invalid Value");
}

try

C# 3.0 Practical Learning II 410


{
subTotal6 =
decimal.Parse(this.txtSubTotal6.Text);
}
catch (FormatException)
{
MessageBox.Show("Invalid Value");
}

// Calculate the total value of the sub totals


orderTotal = subTotal1 + subTotal2 + subTotal3 +
subTotal4 + subTotal5 + subTotal6;

// Display the total order in the appropriate text box


this.txtTotalOrder.Text = orderTotal.ToString();
}

private void lbxPartNumbers_DoubleClick(object sender, EventArgs


e)
{
if (txtPartNumber1.Text == "")
{
// Display the item number in the Part # text
box
txtPartNumber1.Text =
(string)lbxPartNumbers.SelectedItem;
// Display the name of the selected item in
// the current Description text box
txtPartName1.Text =
(string)lbxPartNames.SelectedItem;
// Display the unit price of this item in
// the corresponding Unit Price text box
txtUnitPrice1.Text =
(string)lbxUnitPrices.SelectedItem;
// Since an item was selected, set its quantity
to 1
txtQuantity1.Text = "1";
// Calculate the sub total of the current item
item
txtSubTotal1.Text = txtUnitPrice1.Text;
// Give focus to the Qty text box of the current
item
txtQuantity1.Focus();
}// If the previous Part # text box is not empty, then
use the next one
else if (txtPartNumber2.Text == "")
{
txtPartNumber2.Text =
(string)lbxPartNumbers.SelectedItem;
txtPartName2.Text =
(string)lbxPartNames.SelectedItem;
txtUnitPrice2.Text =
(string)lbxUnitPrices.SelectedItem;

txtQuantity2.Text = "1";
txtSubTotal2.Text = txtUnitPrice2.Text;

C# 3.0 Practical Learning II 411


txtQuantity2.Focus();
}
else if (txtPartNumber3.Text == "")
{
txtPartNumber3.Text =
(string)lbxPartNumbers.SelectedItem;
txtPartName3.Text =
(string)lbxPartNames.SelectedItem;
txtUnitPrice3.Text =
(string)lbxUnitPrices.SelectedItem;

txtQuantity3.Text = "1";
txtSubTotal3.Text = txtUnitPrice3.Text;
txtQuantity3.Focus();
}
else if (txtPartNumber4.Text == "")
{
txtPartNumber4.Text =
(string)lbxPartNumbers.SelectedItem;
txtPartName4.Text =
(string)lbxPartNames.SelectedItem;
txtUnitPrice4.Text =
(string)lbxUnitPrices.SelectedItem;

txtQuantity4.Text = "1";
txtSubTotal4.Text = txtUnitPrice4.Text;
txtQuantity4.Focus();
}
else if (txtPartNumber5.Text == "")
{
txtPartNumber5.Text =
(string)lbxPartNumbers.SelectedItem;
txtPartName5.Text =
(string)lbxPartNames.SelectedItem;
txtUnitPrice5.Text =
(string)lbxUnitPrices.SelectedItem;

txtQuantity5.Text = "1";
txtSubTotal5.Text = txtUnitPrice5.Text;
txtQuantity5.Focus();
}
else if (txtPartNumber6.Text == "")
{
txtPartNumber6.Text =
(string)lbxPartNumbers.SelectedItem;
txtPartName6.Text =
(string)lbxPartNames.SelectedItem;
txtUnitPrice6.Text =
(string)lbxUnitPrices.SelectedItem;

txtQuantity6.Text = "1";
txtSubTotal6.Text = txtUnitPrice6.Text;
txtQuantity6.Focus();
} // If all Part # text boxes are filled, don't do
anything
else

C# 3.0 Practical Learning II 412


return;

CalculateOrder();
}

22. Return to the form and click (once) the lbxPartNames list box

23. In the Events section of the Properties window, double-click Double-Click

24. Implement the event as follows:


 
private void lbxPartNames_DoubleClick(object sender, EventArgs
e)
{
// This event should have been fired already
// But we call it just to be on the safe side
lbxPartNames_SelectedIndexChanged(sender, e);
// Now behave as if the Part Numbers list box was
double-clicked
lbxPartNumbers_DoubleClick(sender, e);
}

25. Return to the form and click (once) the lbxUnitPrices list box

26. In the Events section of the Properties window, double-click Double-Click

27. Implement the event as follows:


 
private void lbxUnitPrices_DoubleClick(object sender, EventArgs
e)
{
lbxUnitPrices_SelectedIndexChanged(sender, e);
lbxPartNumbers_DoubleClick(sender, e);
}

28. Display the form and click the first text box under Qty

29. In the Properties window and in the Events section, double-click the
Leave field

30. Implement the event as follows:


 
private void txtQuantity1_Leave(object sender, EventArgs e)
{
int qty = 0;
decimal unitPrice = 0.00M, subTotal = 0.00M;

// Get the quantity of the current item


try
{
qty = int.Parse(this.txtQuantity1.Text);
}
catch (FormatException)

C# 3.0 Practical Learning II 413


{
MessageBox.Show("Invalid Value");
}

// Get the unit price of the current item


try
{
unitPrice =
decimal.Parse(this.txtUnitPrice1.Text);
}
catch (FormatException)
{
MessageBox.Show("Invalid Value");
}

// Calculate the current sub total


subTotal = qty * unitPrice;

// Display the new sub total in the corresponding


text box
this.txtSubTotal1.Text = subTotal.ToString();
// Update the order
CalculateOrder();
}

31. Return to the form and click the second text box under Qty

32. In the Events section of the Properties window, double-click the Leave
field and implement the event as follows:
 
private void txtQuantity2_Leave(object sender, EventArgs e)
{
int qty = 0;
decimal unitPrice = 0.00M, subTotal = 0.00M;

try
{
qty = int.Parse(this.txtQuantity2.Text);
}
catch (FormatException)
{
MessageBox.Show("Invalid Value");
}

try
{
unitPrice =
decimal.Parse(this.txtUnitPrice2.Text);
}
catch (FormatException)
{
MessageBox.Show("Invalid Value");
}

subTotal = qty * unitPrice;

C# 3.0 Practical Learning II 414


this.txtSubTotal2.Text = subTotal.ToString();

CalculateOrder();
}

33. Return to the form and click the third text box under Qty

34. In the Events section of the Properties window, double-click the Leave
field and implement the event as follows:
 
private void txtQuantity3_Leave(object sender, EventArgs e)
{
int qty = 0;
decimal unitPrice = 0.00M, subTotal = 0.00M;

try
{
qty = int.Parse(this.txtQuantity3.Text);
}
catch (FormatException)
{
MessageBox.Show("Invalid Value");
}

try
{
unitPrice =
decimal.Parse(this.txtUnitPrice3.Text);
}
catch (FormatException)
{
MessageBox.Show("Invalid Value");
}

subTotal = qty * unitPrice;


this.txtSubTotal3.Text = subTotal.ToString();

CalculateOrder();
}

35. Return to the form and click the fourth text box under Qty

36. In the Events section of the Properties window, double-click the Leave
field and implement the event as follows:
 
private void txtQuantity4_Leave(object sender, EventArgs e)
{
int qty = 0;
decimal unitPrice = 0.00M, subTotal = 0.00M;

try
{
qty = int.Parse(this.txtQuantity4.Text);
}

C# 3.0 Practical Learning II 415


catch (FormatException)
{
MessageBox.Show("Invalid Value");
}

try
{
unitPrice =
decimal.Parse(this.txtUnitPrice4.Text);
}
catch (FormatException)
{
MessageBox.Show("Invalid Value");
}

subTotal = qty * unitPrice;


this.txtSubTotal4.Text = subTotal.ToString();

CalculateOrder();
}

37. Return to the form and click the fifth text box under Qty

38. In the Events section of the Properties window, double-click the Leave
field and implement the event as follows:
 
private void txtQuantity5_Leave(object sender, EventArgs e)
{
int qty = 0;
decimal unitPrice = 0.00M, subTotal = 0.00M;

try
{
qty = int.Parse(this.txtQuantity5.Text);
}
catch (FormatException)
{
MessageBox.Show("Invalid Value");
}

try
{
unitPrice =
decimal.Parse(this.txtUnitPrice5.Text);
}
catch (FormatException)
{
MessageBox.Show("Invalid Value");
}

subTotal = qty * unitPrice;


this.txtSubTotal5.Text = subTotal.ToString();

CalculateOrder();
}

C# 3.0 Practical Learning II 416


39. Return to the form and click the sixth text box under Qty

40. In the Events section of the Properties window, double-click the Leave
field and implement the event as follows:
 
private void txtQuantity6_Leave(object sender, EventArgs e)
{
int qty = 0;
decimal unitPrice = 0.00M, subTotal = 0.00M;

try
{
qty = int.Parse(this.txtQuantity6.Text);
}
catch (FormatException)
{
MessageBox.Show("Invalid Value");
}

try
{
unitPrice =
decimal.Parse(this.txtUnitPrice6.Text);
}
catch (FormatException)
{
MessageBox.Show("Invalid Value");
}

subTotal = qty * unitPrice;


this.txtSubTotal6.Text = subTotal.ToString();

CalculateOrder();
}

41. Return to the form

42. Double-click the first Remove button and implement its event as follows:
 
private void btnRemove1_Click(object sender, EventArgs e)
{
txtPartNumber1.Text = "";
txtPartName1.Text = "";
txtUnitPrice1.Text = "0.00";
txtQuantity1.Text = "0";
txtSubTotal1.Text = "0.00";
CalculateOrder();
}

43. Return to the form

C# 3.0 Practical Learning II 417


44. Double-click the second Remove button and implement its event as
follows:
 
private void btnRemove2_Click(object sender, EventArgs e)
{
txtPartNumber2.Text = "";
txtPartName2.Text = "";
txtUnitPrice2.Text = "0.00";
txtQuantity2.Text = "0";
txtSubTotal2.Text = "0.00";
CalculateOrder();
}

45. Return to the form

46. Double-click the third Remove button and implement its event as
follows:
 
private void btnRemove3_Click(object sender, EventArgs e)
{
txtPartNumber3.Text = "";
txtPartName3.Text = "";
txtUnitPrice3.Text = "0.00";
txtQuantity3.Text = "0";
txtSubTotal3.Text = "0.00";
CalculateOrder();
}

47. Return to the form

48. Double-click the fourth Remove button and implement its event as
follows:
 
private void btnRemove4_Click(object sender, EventArgs e)
{
txtPartNumber4.Text = "";
txtPartName4.Text = "";
txtUnitPrice4.Text = "0.00";
txtQuantity4.Text = "0";
txtSubTotal4.Text = "0.00";
CalculateOrder();
}

49. Return to the form

50. Double-click the fifth Remove button and implement its event as follows:
 
private void btnRemove5_Click(object sender, EventArgs e)
{
txtPartNumber5.Text = "";
txtPartName5.Text = "";

C# 3.0 Practical Learning II 418


txtUnitPrice5.Text = "0.00";
txtQuantity5.Text = "0";
txtSubTotal5.Text = "0.00";
CalculateOrder();
}

51. Return to the form

52. Double-click the sixth Remove button and implement its event as
follows:
 
private void btnRemove6_Click(object sender, EventArgs e)
{
txtPartNumber6.Text = "";
txtPartName6.Text = "";
txtUnitPrice6.Text = "0.00";
txtQuantity6.Text = "0";
txtSubTotal6.Text = "0.00";
CalculateOrder();
}

53. Return to the form

54. Double-click the Close button and implement its Click event as follows:
 
private void btnClose_Click(object sender, EventArgs e)
{
Close();
}

C# 3.0 Practical Learning II 419


55. Execute the application to test it
 

56. After using it, close the form

Finding a String in the Combo Box


Instead of simply selecting an item from a combo box, the user may want to
find out if a certain string exists in the  list. To support this operation, the
ComboBox class is equipped with a method named FindString that is
overloaded with two versions. One of the syntaxes of this method is:
public int FindString(string s);

This method takes as argument the string to find in the combo box. If the
item is found in the list, the method returns its position. If the list does not
have that string, the method return -1. The above syntax of the method
would look through the whole list. If you want the search to start at a specific
index, you can use the following version of the FindString() method:
public int FindString(string s, int startIndex);

C# 3.0 Practical Learning II 420


This version takes as the first argument a string. Instead of start looking for it
from the beginning of the list, this method starts at the index specified by the
startIndex value.
The FindString() method performs its operation without regards to case.
This means that it would perform the same search for BlindMan, Blindman,
blindMan, or BLINDMAN and would produce the same result for them. If you
want the case of the characters to be taken into consideration, use the
FindStringExact() method that also is overloaded with two versions. The
syntax of the first version is:
public int FindStringExact(string s);

This method proceeds like the FindString() method by starting to look for the
string from the beginning of the list. If you want to specify from where to
start looking for the string, you should use the following version:
public int FindStringExact(string s, int startIndex);

The Styles of a Combo Box


 
 

The Flat Styles


Like most graphical controls, a combo box appears as a 3-D object with raised
borders. As an alternative, you can display it as a flat object. To assist you
with this choice, the ComboBox class provides the FlatStyle property. The
FlatStyle property is based on the FlatStyle enumeration. Its members are:

 Standard: This is the default value of the property. It makes the control
appear with raised borders:
 
private void InitializeComponent()
{
SuspendLayout();
lblTitle = new Label();
lblTitle.Text = "Academic Disciplines";
lblTitle.Location = new Point(12, 12);
lblTitle.AutoSize = true;

C# 3.0 Practical Learning II 421


Controls.Add(lblTitle);

cbxAcademicDisciplines = new ComboBox();


cbxAcademicDisciplines.Location = new Point(12, 32);
cbxAcademicDisciplines.Width = 232;

cbxAcademicDisciplines.Items.Add("Natural Sciences");
cbxAcademicDisciplines.Items.Add("Mathematics and
Computer Sciences");
cbxAcademicDisciplines.Items.Add("Social Sciences");
cbxAcademicDisciplines.Items.Add("Humanities");
cbxAcademicDisciplines.Items.Add("Professions and
Applied Sciences");

cbxAcademicDisciplines.FlatStyle = FlatStyle.Standard;

Controls.Add(cbxAcademicDisciplines);
}

 Popup: The control will appear flat with a surrounding gray line:
 
cbxAcademicDisciplines.FlatStyle = FlatStyle.Popup;

 Flat: The control appears flat with a white surroundiong border:


 
cbxAcademicDisciplines.FlatStyle = FlatStyle.Flat;

 System: The user's operating system (and theme, if any) will determine
how the control must appear

The Drop Down Style

C# 3.0 Practical Learning II 422


In our introduction to the combo box, we saw that it appeared like a text box
with a down-pointing button on its right side. In reality, that was the
description of just one type of combo box. There are three styles of combo
boxes, although all allow the user to make only one selection. These styles
are controlled by the DropDownStyle property, which is based on the
ComboBoxStyle enumeration.

One of the types of combo boxes is referred to as Drop Down and is created
by setting the DropDownStyle property to DropDown. Here is an example:
private void InitializeComponent()
{
lblTitle = new Label();
lblTitle.Text = "Academic Disciplines";
lblTitle.Location = new Point(12, 12);
lblTitle.AutoSize = true;
Controls.Add(lblTitle);

cbxAcademicDisciplines = new ComboBox();


cbxAcademicDisciplines.Location = new Point(12, 32);
cbxAcademicDisciplines.Items.Add("Natural sciences");
cbxAcademicDisciplines.Items.Add("Mathematics and
Computer sciences");
cbxAcademicDisciplines.Items.Add("Social sciences");
cbxAcademicDisciplines.Items.Add("Humanities");
cbxAcademicDisciplines.Items.Add("Professions and
Applied sciences");

cbxAcademicDisciplines.DropDownStyle =
ComboBoxStyle.DropDown;

Controls.Add(cbxAcademicDisciplines);
}

This type is made of a text box on the left side and a down-pointing arrowed
button on the right side. Depending on how the control was created, when it
comes up, it may not display anything:

Normally, if you want a DropDown style of combo box to display a string when
the control comes up, you can either enter a value in the Text property or
assign a string to the ComboBox.Text property. Here is an example:
private void InitializeComponent()
{

C# 3.0 Practical Learning II 423


lblTitle = new Label();
lblTitle.Text = "Academic Disciplines";
lblTitle.Location = new Point(12, 12);
lblTitle.AutoSize = true;
Controls.Add(lblTitle);

cbxAcademicDisciplines = new ComboBox();


cbxAcademicDisciplines.Location = new Point(12, 32);
cbxAcademicDisciplines.Items.Add("Natural sciences");
cbxAcademicDisciplines.Items.Add("Mathematics and
Computer sciences");
cbxAcademicDisciplines.Items.Add("Social sciences");
cbxAcademicDisciplines.Items.Add("Humanities");
cbxAcademicDisciplines.Items.Add("Professions and
Applied sciences");

cbxAcademicDisciplines.DropDownStyle =
ComboBoxStyle.DropDown;
cbxAcademicDisciplines.Text = "Social sciences";

Controls.Add(cbxAcademicDisciplines);
}

This would produce:

The string you give to the Text property does not have to be one of the
items of the list. 

To use the combo box, the user can click its down pointing arrow. At any
time, to find out whether the list is displaying, you can check the value of the
DroppedDown Boolean property. In the same way, to drop the list, you can
programmatically set the combo box' DroppedDown property to true.

Once the list is displaying, if the user clicks that arrow, a list would appear (or
expand). If the string assigned to the Text property is one of the items in the
list, it would display in the text box side of the control and it would be
selected in the list. Here is an example:
private void InitializeComponent()
{
lblTitle = new Label();
lblTitle.Text = "Academic Disciplines";
lblTitle.Location = new Point(12, 12);
lblTitle.AutoSize = true;
Controls.Add(lblTitle);

C# 3.0 Practical Learning II 424


cbxAcademicDisciplines = new ComboBox();
cbxAcademicDisciplines.Location = new Point(12, 32);
cbxAcademicDisciplines.Items.Add("Natural Sciences");
cbxAcademicDisciplines.Items.Add("Mathematics and
Computer Sciences");
cbxAcademicDisciplines.Items.Add("Social Sciences");
cbxAcademicDisciplines.Items.Add("Humanities");
cbxAcademicDisciplines.Items.Add("Professions and
Applied Sciences");

cbxAcademicDisciplines.DropDownStyle =
ComboBoxStyle.DropDown;
cbxAcademicDisciplines.Text = "Social Sciences";

Controls.Add(cbxAcademicDisciplines);
}

This would produce:

If the string assigned to the Text property is not one of the items in the list, it
would still appear selected in the text box side of the control:

Here is an example:
private void InitializeComponent()
{
lblTitle = new Label();
lblTitle.Text = "Academic Disciplines";
lblTitle.Location = new Point(12, 12);
lblTitle.AutoSize = true;
Controls.Add(lblTitle);

cbxAcademicDisciplines = new ComboBox();


cbxAcademicDisciplines.Location = new Point(12, 32);
cbxAcademicDisciplines.Items.Add("Natural Sciences");
cbxAcademicDisciplines.Items.Add("Mathematics and
Computer Sciences");
cbxAcademicDisciplines.Items.Add("Social Sciences");
cbxAcademicDisciplines.Items.Add("Humanities");
cbxAcademicDisciplines.Items.Add("Professions and
Applied Sciences");

cbxAcademicDisciplines.DropDownStyle =
ComboBoxStyle.DropDown;

C# 3.0 Practical Learning II 425


cbxAcademicDisciplines.Text = "Arts & Sciences";

Controls.Add(cbxAcademicDisciplines);
}

This would produce:

When the list displays, either because the user clicked the arrow button,
pressed Alt + the down arrow key or because you decided to display it, the
control fires a DropDown event, which is of type EventArgs.
If the user sees an item that he or she wants or was asked to select, he or she
can click it. After an item has been clicked, two things happen: 1. the list retracts
(or collapses) like a plastic; 2. the item that was clicked fills the text part and
becomes the new selection:

On the other hand, after displaying the list, if the user doesn't want to select
anything from the list, he or she can click the arrow again or click anywhere
away from the list. The list would collapse and the text part would get back to
the previous text.

One of the major characteristics of a DropDown style of combo box, as


compared to the type we will see next, is that, if the user knows for sure that the
item he or she is looking for is in the list, he can first delete the string in the text
box part of the control, then start typing. For example, if the list contains a string
such as Social Sciences , the user can delete the text part, and start typing so. If
there is only one item that starts with s, the user can then click the arrow twice
and the item would be selected. Imagine the list contains such items as Jules and
Julienne, if the user types the first common letters of these item and double-click
the arrow, the first item that has these letters would be selected. This means
that, if the user wants to other item to be selected, he or she should type the

C# 3.0 Practical Learning II 426


letters beyond the common ones. In the case of Jules and Julienne, if the user
wants Julienne to be selected from an incomplete string, he or she can type juli
and click the arrowed button twice.

The Drop Down List


Another style of combo box is gotten by setting the DropDownStyle to
DropDownList. This type also is made of a text box on the left and a down-
pointing arrowed button on the right side. It also may appear empty when it
comes up, depending on how it was created. The biggest difference between
a DropDown combo box and a DropDownList combo box is that, with the
drop down list, the user can only select from the list: he or she cannot type
anything in the text box part of the control.

Once again, to use the control, the user can click its arrow, which causes the
list to display. The user can also display the list using the keyboard by
pressing Alt + down arrow key after giving focus to the control.

The Simple Combo Box


The last type of combo box is called a simple combo box and is gotten by
setting the DropDownStyle to Simple. After setting this value, you must
heighten the control to get the desired size. This type of combo box is also
made of two parts but they are distinct. The top section of the combo box
displays a text box. Immediately under the text box, there is a list box. The
following is the Character dialog box of OpenOffice.org. Its Font property
page is equipped with the Font, the Typeface, and the Size combo boxes that
are of a Simple style:

C# 3.0 Practical Learning II 427


Notice that the control doesn't display a down-arrow pointing button on the
right side of the selected item since the list is available already. To use this
combo box, the user can examine the list part. If he or she sees the desired
item, he can click it. When an item is clicked, it becomes the string of the top
text part. If the user clicks a different item, it would become the new
selection, replacing the one that was in the text part. Although this appears
as a list box, the user cannot select more than one item.

The most regularly used combo boxes are made of text items. You can also
create a combo box that displays colors or pictures. To create such a combo
box, you start by changing the value of the DrawMode property that is set to
Normal by default. If you want to display items that are not just regular text,
you can set this property to either OwnerDrawFixed, which would make all
items have the same height, or OwnerDrawVariable, which allows different
items to have different sizes.

If the combo box has a DropDownStyle other than Simple, there is typically
a fixed number of items that display when the user clicks the control’s arrow.
You can control the number of items that displays using the
MaxDropDownItems property. By default, this is set to 8. If the list contains a
number of items less than the MaxDropDownItems integer value, all of the
items would display fine. If the list contains more than the
MaxDropDownItems number of items, when the user clicks the arrow, a
vertical scroll box would appear. The control would display

C# 3.0 Practical Learning II 428


MaxDropDownItems number of items; to reveal more, the user would have to
scroll in the list.

The Combo Box: Automatic List


Creation
 

Using an External List


 

In the next previous sections, we saw how to create a list of items. The .NET
Framework provides an alternative. Instead of creating a list from scratch,
you can use one that exists already. For example, you can use a list of
recently accessed web sites or custom list of your own. To assist you with
this, the ComboBox class provides with three techniques.

To specify an external list of items to use for the combo box, you have two
options. You can use the AutoCompleteSource property, that is based on the
AutoCompleteSource enumeration. The members of this enumeration are:
None, RecentlyUsedList, FileSystem, FileSystemDirectories,
HistoryList, ListItems, AllSystemSources, AllUrl, and CustomSource.
Imagine that you want to use the list of web pages you had visited lately. To
use that list, you can specify the AutoCompleteSource as HistoryList.

After specifying the source of the list, use the AutoCompleteMode property to
specify how the combo box (or rather the text box side of the control) will
assist the user. This property is based on the AutoCompleteMode
enumeration that has four members. None is the default value. Imagine you
had set the value of the AutoCompleteSource property as HistoryList. If
you specify AutoCompleteMode as:

 Suggest: In the text box part of the combo box, the user can click and
start typing. A list of closely-matched items would display:
 

C# 3.0 Practical Learning II 429


In this case, as soon as the user types h, a list of URLs that start with h
(for http) would come up. Once the user sees the desired item, he or she
can then click that item to select it. Since there are many items, to
continuously narrow the list, the user can keep typing until the desired
item comes up

 Append: In the text box part, the user can start typing. The control would
then start looking for the closest matches and try to complete the user's
entry with those available. Here is an example:
 

 First the user types h and http:// comes up as the first closest match.
Then, the user specifies that the address starts with m and the
compiler suggests, in alphabetical order, the closest URL with that.
Then, the user types ms and finds out that msdn2 is available

 SuggestAppend: This is a combination of the previous two options.


When the control comes up, the user can start typing. The control would
then display the list of items that start with what the user typed and it
would display the starting closest match

C# 3.0 Practical Learning II 430


 

The user can continue typing. If the desired item appears in the list, the user can
select it. Otherwise, as the user is typing, the closest match displays in the text
box part of the control
 

Using a Custom List


 

Instead of using an external list, you can create your own. To do this, use the
AutoCompleteCustomSource property. At design time, to create a list of
strings, access the Properties window for the text box. In the Properties
window, click the ellipsis button of the AutoCompleteCustomSource field to
open the String Collection Editor. Enter the strings separated by a hard
Return, and click OK. You can also programmatically create the list. To assist
you, the .NET Framework provides a class named
AutoCompleteStringCollection. The AutoCompleteStringCollection
class implements the IList, the ICollection, and the IEnumerable
interfaces.

After creating the custom list, to let the combo box use it, set the
AutoCompleteMode property to CustomSource.

C# 3.0 Practical Learning II 431


Accessories for Control Design: The
Flow Layout Panel
 

Introduction
To further assist you with application design, the .NET Framework provides
the flow layout panel that you can use instead of manually positioning your
controls horizontally or vertically. When used horizontally, the flow layout
panel takes care of aligning controls so that all of them would have the same
distance from the top border of their container. Of course, this has to do
only with the controls that belong to the same group (the same container).

The flow layout panel is represented in the .NET Framework by  the
FlowLayoutPanel class and in the Toolbox by the FlowLayoutPanel object.
Therefore, to use it, click it from the Toolbox and add it to your form. The
flow layout panel appears as a dotted rectangular object:

After placing it on a form, you can add controls to it. To do this, you would
click a control from the Toolbox and click inside the flow layout panel. When
you add the first control, it gets positioned in the top left side of the container
and you cannot move it to a different position (if this were done it would
deceive the purpose of the flow layout panel):

When you add a second control to the flow layout panel, it is positioned on
the right side of the previously added control with the same horizontal
alignment. You can continue adding other controls. If you want the controls
to be aligned vertically, resize the flow layout panel accordingly:

C# 3.0 Practical Learning II 432


Instead of aligning controls horizontally, you may want to position them
vertically. To do this, you can narrow the flow layout panel but heighten it:

In the same way, if the flow layout panel is narrow and the controls are
positioned vertically, if you enlarge it, its control would be positioned horizontally.
As you can see, the flow layout panel provides a convenient way of aligning
controls.

Characteristics of the Flow Layout Panel


We mentioned that when you add the first control to a flow layout panel, the
control is positioned in the top-left section of the container and the
subsequently added controls would be positioned on the right side of, or
below, the previous control. This is the default behavior and it is referred to
as left-to-right. You can change this aspect. Depending on your design
intentions, you may want the controls to be positioned from right to left. This
characteristic is controlled by the FlowDirection property, which is an
enumeration. The default value of this property is LeftToRight. If you set it
to RightToLeft, the first control would be added to the top-right section of
the container, the other controls would be incrementally positioned to the left
of the previous one(s).

As mentioned above, after adding a flow layout panel to a form, if you add a
control to it, the control is positioned in the top-left section. If you add a
second control, it is positioned on the right side of the previous control. This
would be the same with the other subsequent controls. If you add a control
but there is no room on the right side, the control would be positioned on the
next row. If you resize the flow layout panel, the controls would be aligned

C# 3.0 Practical Learning II 433


vertically. This is the default behavior and it is referred to as wrapping. This
means that the flow layout panel has the ability to wrap the controls inside its
client area. This characteristics is partly controlled by a Boolean property
named WrappingContents. Its default value is set to True. This property is
controlled in connection with the FlowDirection.

The Characteristics of a Button


 

The Caption of a Button


For a user, the most important aspects of a button are the message it
displays and the action it performs. The text the button displays allows the
user to know what the button is used for. This is represented by the Text
property. The most popular strings that the buttons display are OK and
Cancel. The OK caption is set for a form or a dialog box that informs the user
of an error, an intermediary situation, or an acknowledgement of an action
that was performed on the dialog that hosts the button. The Cancel caption is
useful on a button whose main parent (the form or the dialog box) would ask
a question or request a follow-up action from the user. Whenever a dialog
box allows the user to dismiss it without continuing the action, you should
provide a button with a Cancel caption.

After adding a button to a form (by design or with code), you can change its
caption with code by assigning the desired string to the Text property. For
example, you can change the caption of a button as follows:
button1.Text = "Let it Go!";

After specifying the Text of a button, by default, it's positioned in the middle
center of the button:

The position of the text of a button is controlled through the TextAlign


property which is a value of the ContentAlignment enumerator. The
possible values are:

C# 3.0 Practical Learning II 434


TopLeft TopCenter TopRight

MiddleLeft MiddleCenter MiddleRight

BottomLeft BottomCenter BottomRight

Here is an example:
public class Exercise : System.Windows.Forms.Form
{
Button btnResume;

public Exercise()
{
InitializeComponent();
}

private void InitializeComponent()


{
btnResume = new Button();
btnResume.Text = "Resume";
btnResume.Location = new Point(32, 20);
btnResume.Size = new System.Drawing.Size(120, 48);
btnResume.TextAlign = ContentAlignment.BottomCenter;

Controls.Add(btnResume);
}
}

Practical Learning: Using the Buttons

1. Access each tab page and add a button to it

2. Add a button to the form and under the tab control

C# 3.0 Practical Learning II 435


3. Complete the design of the form as follows:
 

Control Text Name

Button Calculate btnCalcFactorial

Button Close btnClose

Control Text Name

Button Calculate btnCalcPermutation

C# 3.0 Practical Learning II 436


Control Text Name

Button Calculate btnCalcCombination

4. Access the Factorial tab page and double-click its Calculate button

5. Implement the event as follows:


 
private void btnCalcFactorial_Click(object sender, EventArgs e)
{
long number = 0;
long result;

try
{
number = long.Parse(txtFactNumber.Text);
result = Algebra.Factorial(number);
txtFactorial.Text = result.ToString();
}
catch (FormatException)
{
MessageBox.Show("Invalid Number");
}
}

6. Return to the form

7. Access the Permutation tab page and double-click its Calculate button

8. Implement the event as follows:


 
private void btnCalcPermutation_Click(object sender, EventArgs
e)
{
long n = 0, r = 0;
long result;

C# 3.0 Practical Learning II 437


try
{
n = long.Parse(txtPermutationN.Text);
}
catch (FormatException)
{
MessageBox.Show("Invalid Number");
}

try
{
r = long.Parse(txtPermutationR.Text);
result = Algebra.Permutation(n, r);
txtPermutation.Text = result.ToString();
}
catch (FormatException)
{
MessageBox.Show("Invalid Number");
}
}

9. Return to the form

10. Access the Combination tab page and double-click its Calculate button

11. Implement the event as follows:


 
private void btnCalcCombination_Click(object sender, EventArgs
e)
{
long n = 0, r = 0;
long result;

try
{
n = long.Parse(txtCombinationN.Text);
}
catch (FormatException)
{
MessageBox.Show("Invalid Number");
}

try
{
r = long.Parse(txtCombinationR.Text);
result = Algebra.Combinatorial(n, r);
txtCombination.Text = result.ToString();
}
catch (FormatException)
{
MessageBox.Show("Invalid Number");
}
}

12. Return to the form and double-click the Close button

C# 3.0 Practical Learning II 438


13. Implement the event as follows:
 
private void btnClose_Click(object sender, EventArgs e)
{
Close();
}

14. Execute the application to test the calculations


 

C# 3.0 Practical Learning II 439


15. Close the form and return to your programming environment

The Image on a Button


Besides, or instead, of a caption, a button can display a picture on top. If you
want a button to display a bitmap, you should first create, design, or have a
picture. Then, in the Properties window, use the Image field to select a
bitmap or an icon. You can also programmatically assign an Image object to
the Image property. Here is an example:
private void InitializeComponent()
{
btnResume = new Button();
btnResume.Text = "Resume";
btnResume.Location = new Point(32, 20);
btnResume.Size = new System.Drawing.Size(120, 48);
btnResume.Image =
Image.FromFile(@"E:\Programs\neutral.gif");

Controls.Add(btnResume);
}

This would produce:

By default, both the caption and the image display ion the middle-center of
the button. To make them distinct and allow the user to see both, you can
design a bitmap that has both and assign that bitmap as the image of the
button. Alternatively, you can use a separate string and a separate picture.
Fortunately, each can have its own alignment. We already saw how to control
the alignment of the caption.

Besides displaying an image, the Button class is equipped with the


ImageAlign property that allows you to specify the alignment of the image.
The ImageAlign property is inherited from the ButtonBase class. The
ButtonBase.ImageAlign property is based on the ContentAlignment
enumeration that we are already familiar with. Here is an example:
private void InitializeComponent()
{
btnResume = new Button();
btnResume.Location = new Point(32, 20);
btnResume.Size = new System.Drawing.Size(120, 48);
btnResume.Text = "Resume";
btnResume.TextAlign = ContentAlignment.BottomCenter;

C# 3.0 Practical Learning II 440


btnResume.Image =
Image.FromFile(@"E:\Programs\neutral.gif");
btnResume.ImageAlign = ContentAlignment.TopCenter;

Controls.Add(btnResume);
}

This would produce:

Instead of using the Image property, you can first create an image list and
add some pictures to it. Then, using the ImageList property, assign it to the
button. Use the ImageIndex property to specify what picture would be
displayed on the button.

The Flat Style of a Button


A regular button displays with raised borders as originally set by the operating
system. To give your button a fancy look and behavior, you can use the
FlatStyle property. The FlatStyle property is based on an enumeration of
the same name. It provides 4 values that are:

 Flat: The button appears flat. When the mouse is over it, it becomes
highlighted

 Popup: The button appears flat. When the mouse is over it, the borders
of the button are raised

 Standard: The button appears and behave like all regular buttons you
have seen

 System: The appearance of the button depends on the operating system

Obviously the most important and the most intuitive event of a button occurs
when clicked. This event is of type EventArgs, which indicates that it doesn't
provide nor does it need any formal details about what is going on. To launch
this event, you can double-click the button on the form. To create this event
programmatically, first implement the method that would carry its
assignment, then increment-add (with the += operator) it to the Click
property of the button by assigning it the EventHandler constructor.

The Result of a Dialog Box


After the user has used a form or dialog box, to close it, the user would click
a button. When the user does this, you must find out what button was

C# 3.0 Practical Learning II 441


clicked. Although there are various ways you can get this information, to
assist you, the .NET Framework provides a convenient mechanism through an
enumeration named DialogResult.

When creating a form or a dialog box, after adding a button, in the Properties
window, click DialogResult and select on the values:

Except for None, by default, it does not matter what value you select but, you
should follow Windows standard to select the right value.

After specifying the returned value of a button, access the properties of the
form or dialog box:

 If you had selected OK as the DialogResult value of a button, you


should select the name of that button for the AcceptButton property of
the form

 If you had selected Cancel as the DialogResult value of a button, you


should select the name of that button for the CancelButton property of
the form

After configuring the DialogResult of the button(s), when the user clicks
one of the buttons to close the form or dialog box, you can get the value of
the Form.ShowDialog() method which returns one of the values of the
DialogResult enumeration.

Applications:
Algebra

Simple Interest

C# 3.0 Practical Learning II 442


Windows Control: The Link Label
 

Introduction
In the past, to add an internet or email link to a form, there were many
steps to follow. As the internet and email had become an integral part of the
culture, it was also time to have an appropriate control adapted for this need.
To address this issue, a control called LinkLabel is available from the .NET
Framework.

Characteristics of the Link Label


As its name indicates, the LinkLabel control allows you to create a link. If
you have done web development, you would know that a link can be made
fancy by varying its colors. A link typically uses three different colors (actually,
if you use cascading style sheet, you can add a fourth color as hover):

 Link: This is the general color used on a link that a user has not clicked
before. The LinkLabel class defines this color through the LinkColor
property.

 Active Link: When the user clicks a link, its target typically opens if
everything is alright. This causes the link to change its color status. The
color of an active link is represented in the LinkLabel class with the
ActiveLinkColor property.

 Visited: When a user comes to a page or the document that provides a


link, you can indicate whether the link was previously accessed or not.
This is done by displaying a color other than the link color. The color of a
previously visited link is represented in the LinkLabel class by the
VisitedLinkColor property.

After creating a link, when the user accesses it, you can define some behavior
the link would exhibit to the user, such as getting underlined or not
underlined when the mouse passes over the link. The behaviors of a link can
be controlled through the LinkBehavior property whose values are
AlwaysUnderline, HoverUnderline, NeverUnderline, or the application
would refer to Internet Options dialog box of Control Panel.

A link is typically meant to help the user switch to a different page or


document when clicked. In some cases and at a particular time, you may not
want the user to be able to click a link. In this case you can disable it. If you

C# 3.0 Practical Learning II 443


decide to disable a link, you can change its color using the
DisabledLinkColor property. On the other hand, if the user is not able to
access a link, that is, if a link is disabled, you can find out the color of that
link from the DisabledLinkColor property.

Here is an example:
private void linkLabel1_LinkClicked(object sender,
LinkLabelLinkClickedEventArgs e)
{
System.Diagnostics.Process.Start(
@"C:\Program Files\Internet
Explorer\iexplore.exe",
"http://www.functionx.com/vccli");
}

Windows Control: The Month


Calendar
 

Description
Microsoft Windows provides a control used to select dates on a colorful
calendar:

The dates used and the way they display are based on the Regional Settings
of the Control Panel. It may also depend on the operating system. This
convenient control is called month calendar or simply calendar. The title bar
of the control displays two buttons and two labels. The left button allows the
user to select the previous month by clicking the button. The left label
displays the currently selected month. The right label displays the year of the
displayed date. The right button is used to get to the next month.

The calendar can be configured to display more than one month. Here is an
example that displays two months:

C# 3.0 Practical Learning II 444


If the control is displaying more than one month, the buttons would
increment or decrement by the previous or next month in the list. For
example, if the control is displaying April and May and if the user clicks the
left button, the control would display March and April. If the control is
displaying April and May and the user clicks the right button, the control
would display May and June. Also, to select any month of the current year,
the user can click the name of the month, which displays the list of months
and this allows the user to click the desired month:

To select a year, the user can click the year number. This changes the year
label into a spin button:

C# 3.0 Practical Learning II 445


To change the year, the user can click the up or down arrows of the spin
button. As the spin button is displaying, the user can also use the arrow keys
of the keyboard to increase or decrease the value.

Under the title bar, the short names of week days display, using the format
set in Control Panel. In US English, the first day is usually Sunday. The first
day can be changed by the programmer.

On the control, the currently selected date has a circle around. To select a
date on the control, the user clicks the desired date, which changes from the
previous selection.

In the main area, the numeric days of the month display on a white
background (this color and any color on the control can be changed as we
will see in the next section). To select a date, the user clicks it in the list. By
default, the calendar opens with today's day circled with a hand-drawn-look-
alike ellipse. Using the buttons of the title bar, the month label, and/or the
year, the user can change the date. If at one time the calendar is displaying a
date other than today, and if the user wants to return to today's date, he or
she can click the bottom label that displays Today (you as the programmer
can hide the Today label if you want).

Creating a Calendar

To create a calendar control, you can click the MonthCalendar button in


the Toolbox and click the form or the desired container. The MonthCalendar
control is based on the MonthCalendar class, which is based on Control.
Therefore, to create a calendar control, declare a variable or type
MonthCalendar and initialize it appropriately.

Practical Learning: Introducing the Month Calendar


Control

1. Start a new Windows Application named PayrollProcessing2

2. In the Solution Explorer, right-click Form1.cs and click Rename

3. Type PayrollProcessing.cs and press Enter

4. Design the form as follows:


 

C# 3.0 Practical Learning II 446


Control Name Text Other Properties

GroupBox   Employee Identification  

Label   &Employee Name:  

TextBox txtEmployeeName   AutoCompleteCustomSource


Micheline Hammond
Paul Bertrand Yamaguchi
Gertrude Monay
Ernestine Ngaleu
Andy Barang
Christophe Yuen
Jean Michel Kankan

AutoCompleteSource: CustomSource

AutoCompleteMode: Accept

C# 3.0 Practical Learning II 447


 

Label   Hourly &Salary:  

TextBox txtHourlySalary    

GroupBox Payroll Time Frame

MonthCalendar calTimeFrame Cursor: Hand

GroupBox   Time Values  

Label   Monday  

Label   Tuesday  

Label   Wednesday  

Label   Thursday  

Label   Friday  

Label   Saturday  

Label   Sunday  

Label   First Week:  

TextBox txtMonday1 0.00 TextAlign: Right

TextBox txtTuesday1 0.00 TextAlign: Right

TextBox txtWednesday1 0.00 TextAlign: Right

TextBox txtThursday1 0.00 TextAlign: Right

TextBox txtFriday1 0.00 TextAlign: Right

TextBox txtSaturday1 0.00 TextAlign: Right

TextBox txtSunday1 0.00 TextAlign: Right

C# 3.0 Practical Learning II 448


Label   Second Week:  

TextBox txtMonday2 0.00 TextAlign: Right

TextBox txtTuesday2 0.00 TextAlign: Right

TextBox txtWednesday2 0.00 TextAlign: Right

TextBox txtThursday2 0.00 TextAlign: Right

TextBox txtFriday2 0.00 TextAlign: Right

TextBox txtSaturday2 0.00 TextAlign: Right

TextBox txtSunday2 0.00 TextAlign: Right

GroupBox   Payroll Processing  

Label   Hours  

Label   Amount  

Button btnCalculate Calculate  

Label   Regular  

TextBox txtRegularTime 0.00 TextAlign: Right

TextBox txtRegularAmount 0.00 TextAlign: Right

Label   Net Pay:  

TextBox txtNetPay 0.00 TextAlign: Right

Label   Overtime  

TextBox txtOvertime 0.00 TextAlign: Right

TextBox txtOvertimeAmount0.00 TextAlign: Right

Button btnClose    

C# 3.0 Practical Learning II 449


5. On the form, double-click the Calculate button and implement its event
as follows:
 
private void btnCalculate_Click(object sender, EventArgs e)
{
double monday1 = 0.00, tuesday1 = 0.00, wednesday1 =
0.00,
thursday1 = 0.00, friday1 = 0.00, saturday1
= 0.00,
sunday1 = 0.00, monday2 = 0.00, tuesday2 =
0.00,
wednesday2 = 0.00, thursday2 = 0.00,
friday2 = 0.00, saturday2 = 0.00, sunday2 = 0.00;
double totalHoursWeek1, totalHoursWeek2;

double regHours1 = 0.00, regHours2 = 0.00,


ovtHours1 = 0.00, ovtHours2 = 0.00;
double regAmount1 = 0.00, regAmount2 = 0.00,
ovtAmount1 = 0.00, ovtAmount2 = 0.00;
double regularHours, overtimeHours;
double regularAmount, overtimeAmount, totalEarnings;

double hourlySalary = 0.00;

// Retrieve the hourly salary


try
{
hourlySalary =
double.Parse(txtHourlySalary.Text);
}
catch (FormatException)
{
MessageBox.Show(
"The value you typed for the salary is
invalid \n" +
"Please try again");
txtHourlySalary.Focus();
}

// Retrieve the value of each day worked


try
{
monday1 = double.Parse(txtMonday1.Text);
}
catch (FormatException)
{
MessageBox.Show("You typed an invalid value\n" +
"Please try again");
txtMonday1.Focus();
}
try
{

C# 3.0 Practical Learning II 450


tuesday1 = double.Parse(txtTuesday1.Text);
}
catch (FormatException)
{
MessageBox.Show("You typed an invalid value\n" +
"Please try again");
this.txtTuesday1.Focus();
}
try
{
wednesday1 = double.Parse(txtWednesday1.Text);
}
catch (FormatException)
{
MessageBox.Show("You typed an invalid value\n" +
"Please try again");
txtWednesday1.Focus();
}
try
{
thursday1 = double.Parse(txtThursday1.Text);
}
catch (FormatException)
{
MessageBox.Show("You typed an invalid value\n" +
"Please try again");
txtThursday1.Focus();
}

try
{
friday1 = double.Parse(txtFriday1.Text);
}
catch (FormatException)
{
MessageBox.Show("You typed an invalid value\n" +
"Please try again");
txtFriday1.Focus();
}

try
{
saturday1 = double.Parse(txtSaturday1.Text);
}
catch (FormatException)
{
MessageBox.Show("You typed an invalid value\n" +
"Please try again");
txtSaturday1.Focus();
}

try
{
sunday1 = double.Parse(txtSunday1.Text);
}
catch (FormatException)

C# 3.0 Practical Learning II 451


{
MessageBox.Show("You typed an invalid value\n" +
"Please try again");
txtSunday1.Focus();
}
try
{
monday2 = double.Parse(txtMonday2.Text);
}
catch (FormatException)
{
MessageBox.Show("You typed an invalid value\n" +
"Please try again");
this.txtMonday2.Focus();
}
try
{
tuesday2 = double.Parse(txtTuesday2.Text);
}
catch (FormatException)
{
MessageBox.Show("You typed an invalid value\n" +
"Please try again");
this.txtTuesday2.Focus();
}
try
{
wednesday2 = double.Parse(txtWednesday2.Text);
}
catch (FormatException)
{
MessageBox.Show("You typed an invalid value\n" +
"Please try again");
this.txtWednesday2.Focus();
}
try
{
thursday2 = double.Parse(txtThursday2.Text);
}
catch (FormatException)
{
MessageBox.Show("You typed an invalid value\n" +
"Please try again");
txtThursday2.Focus();
}
try
{
friday2 = double.Parse(txtFriday2.Text);
}
catch (FormatException)
{
MessageBox.Show("You typed an invalid value\n" +
"Please try again");
txtFriday2.Focus();
}
try

C# 3.0 Practical Learning II 452


{
saturday2 = double.Parse(txtSaturday2.Text);
}
catch (FormatException)
{
MessageBox.Show("You typed an invalid value\n" +
"Please try again");
txtSaturday2.Focus();
}
try
{
sunday2 = double.Parse(txtSunday2.Text);
}
catch (FormatException)
{
MessageBox.Show("You typed an invalid value\n" +
"Please try again");
txtSunday2.Focus();
}

// Calculate the total number of hours for each week


totalHoursWeek1 = monday1 + tuesday1 + wednesday1 +
thursday1 + friday1 + saturday1 + sunday1;
totalHoursWeek2 = monday2 + tuesday2 + wednesday2 +
thursday2 + friday2 + saturday2 + sunday2;

// The overtime is paid time and half


double ovtSalary = hourlySalary * 1.5;

// If the employee worked under 40 hours, there is


no overtime
if (totalHoursWeek1 < 40)
{
regHours1 = totalHoursWeek1;
regAmount1 = hourlySalary * regHours1;
ovtHours1 = 0.00;
ovtAmount1 = 0.00;
} // If the employee worked over 40 hours, calculate
the overtime
else if (totalHoursWeek1 >= 40)
{
regHours1 = 40;
regAmount1 = hourlySalary * 40;
ovtHours1 = totalHoursWeek1 - 40;
ovtAmount1 = ovtHours1 * ovtSalary;
}

if (totalHoursWeek2 < 40)


{
regHours2 = totalHoursWeek2;
regAmount2 = hourlySalary * regHours2;
ovtHours2 = 0.00;
ovtAmount2 = 0.00;
}
else if (totalHoursWeek2 >= 40)
{

C# 3.0 Practical Learning II 453


regHours2 = 40;
regAmount2 = hourlySalary * 40;
ovtHours2 = totalHoursWeek2 - 40;
ovtAmount2 = ovtHours2 * ovtSalary;
}

regularHours = regHours1 + regHours2;


overtimeHours = ovtHours1 + ovtHours2;
regularAmount = regAmount1 + regAmount2;
overtimeAmount = ovtAmount1 + ovtAmount2;
totalEarnings = regularAmount + overtimeAmount;

txtRegularTime.Text = regularHours.ToString("F");
txtOvertime.Text = overtimeHours.ToString("F");
txtRegularAmount.Text = regularAmount.ToString("F");
txtOvertimeAmount.Text =
overtimeAmount.ToString("F");

txtNetPay.Text = totalEarnings.ToString("F");
}

6. Save the form

Using a Month Calendar Control


 

Selecting a Date
As mentioned in our description, the calendar control displays the days of a
selected month. The control also displays the remaining days, if any, of the
first week of the currently selected month; that is, the days of the previous
month that share the week with the first day of the first week of the selected
month. The control also displays the first days of the subsequent month that
share the week with the last day of the current month.

To use the calendar control, the user can click a date, whether it a date from
the current month or a day of the other (previous and next) month. When the
user has clicked a date to select it, the control fires a DateSelected event.
The DateSelected event is of type DateRangeEventArgs.

The user can also select a date using the keyboard. To do this, the user
must first give focus to the control. This is possible by pressing Tab
continuously until the control receives focus (or by clicking any date on the
control. To select a date using the keyboard, the user can continually press
one of the arrow keys (on the keyboard) until the desired date is selected.

C# 3.0 Practical Learning II 454


You too can programmatically select a date on the calendar control. To do
this, assign a valid DateTime value to both the SelectionStart and the
SelectionEnd properties. Here is an example:

private void btnSelect_Click(object sender, EventArgs e)


{
monthCalendar1.SelectionStart = new DateTime(1988, 12,
5);
monthCalendar1.SelectionEnd = new DateTime(1988, 12, 5);
}

When a date has been selected, whether by the user (using the mouse or the
keyboard) or by you (through code), the control fires a DateChanged event.
The DateChanged event is of type DateRangeEventArgs.

The DateRangeEventArgs class is equipped with two properties: Start and


End. When the user clicks a date, these two properties hold the date that was
clicked. This means that you can use either of these properties to know the
date that was clicked. Both the Start and the End properties are of type
DateTime.

Practical Learning: Showing Two Months

1. On the form, click the calendar control

2. In the Properties window, click the Events button and double-click


DateSelected

3. Implement the event as follows:


 
private void calTimeFrame_DateSelected(object sender,
DateRangeEventArgs e)
{
DateTime DateStart = e.Start;
if (DateStart.DayOfWeek != DayOfWeek.Monday)
MessageBox.Show("The first day of your time frame must be
a Monday");
}

4. Execute the application and try selecting a range of dates

5. Close the form and return to your programming environment

The Date Range Selection


When the user clicks the calendar control, one date is selected. As mentioned
in our description, you can give the control the ability to display more than
one month. To make this possible, when creating the control, set its width to
have enough space. In the same way, you can increase the height to display
many months.

C# 3.0 Practical Learning II 455


To select more than one date, the user can click one date, hold the mouse
down, and drag to the left, the right, up or down:

The user can also select a range of dates using the keyboard or using a
combination of the mouse and the keyboard. To do this, the user must first
give focus to the control. To select a range of dates using the keyboard, the
user can press and hold Shift, then press one of the arrow keys continually
until the last date of the desired range is selected (in reality, we will see that
there is a property that controls the maximum range of dates that can be
selected). To select a range of dates using a combination of the mouse and
keyboard, the user can click the first date, press and hold Shift, then click
the last date.

After selecting the days, the starting date is stored in the SelectionStart
property. The last date of the selection is stored in the SelectionEnd
property. Both properties are of DateTime type. The range of the selected
dates is stored in a SelectionRange value. SelectionRange is simply a
class that can give you information about the beginning and the end of a
selected range of dates.

To programmatically select a date, assign the starting to the


SelectionStart property and assign the last date to the SelectionEnd
property.

By default, the user can select only up to 7 days at a time. If you want the
user to be able to select more or less days than that. Here is an example
where the user have selected dates from the 11 to the 20th, that is 10 days:

C# 3.0 Practical Learning II 456


If you configure the control to display more than one month, the user can
select days from one month to another as long as the days are in a range.
Here is an example of a calendar that displays two months and the user had
selected dates from September 21st, 2007 to October 11th, 2007:

After selecting a range of dates, the control fires a DateChanged event, which
is of type DateRangeEventArgs. We saw earlier that the
DateRangeEventArgs class has two properties. The
DateRangeEventArgs.Start property holds the starting date of the range
that the user made. The DateRangeEventArgs.End holds the last date from
the range that the user made.

Practical Learning: Showing Two Months

1. On the form, click the calendar control and drag its right border so it can
display two months:

C# 3.0 Practical Learning II 457


 

2. Right-click the form and click View Code

3. Change the DateSelected event as follows:


 
void EnableForInvalidDate(bool Enable)
{
if (Enable == true)
{
txtMonday1.Enabled = true; txtMonday2.Enabled =
true;
txtTuesday1.Enabled = true; txtTuesday2.Enabled =
true;
txtWednesday1.Enabled = true; txtWednesday2.Enabled =
true;
txtThursday1.Enabled = true; txtThursday2.Enabled =
true;
txtFriday1.Enabled = true; txtFriday2.Enabled =
true;

C# 3.0 Practical Learning II 458


txtSaturday1.Enabled = true; txtSaturday2.Enabled =
true;
txtSunday1.Enabled = true; txtSunday2.Enabled =
true;
txtRegularTime.Enabled = true; txtRegularAmount.Enabled
= true;
txtOvertime.Enabled = true; txtOvertimeAmount.Enabled =
true;
txtNetPay.Enabled = true; btnCalculate.Enabled = true;
}
else if (Enable == false)
{
txtMonday1.Enabled = false; txtMonday2.Enabled = false;
txtTuesday1.Enabled = false; txtTuesday2.Enabled =
false;
txtWednesday1.Enabled = false; txtWednesday2.Enabled =
false;
txtThursday1.Enabled = false; txtThursday2.Enabled =
false;
txtFriday1.Enabled = false; txtFriday2.Enabled = false;
txtSaturday1.Enabled = false; txtSaturday2.Enabled =
false;
txtSunday1.Enabled = false; txtSunday2.Enabled = false;
txtRegularTime.Enabled = false; txtRegularAmount.Enabled
= false;
txtOvertime.Enabled = false; txtOvertimeAmount.Enabled =
false;
txtNetPay.Enabled = false; btnCalculate.Enabled = false;
}
}

private void calTimeFrame_DateSelected(object sender,


DateRangeEventArgs e)
{
DateTime DateStart = e.Start;
// Each payroll will cover 2 weeks
// This application assumes that the company started
// implementing the time sheet on January 1st, 2007
// Our week day will go from Monday of the first week
// to Sunday of the following week
// The first date of the time frame must be a Monday
if (DateStart.DayOfWeek != DayOfWeek.Monday)
{
MessageBox.Show("The first day of your time frame must
be a Monday");
EnableForInvalidDate(false);
return;
}
else
EnableForInvalidDate(true);

// Now that the user has selected a date that starts on


Monday,
// We will check that it corresponds to
// 2 weeks by 2 weeks after January 1st, 2007
// To start, we must get the difference of days between

C# 3.0 Practical Learning II 459


// the selected starting date and January 1st, 2007
TimeSpan tmDifference = DateStart.Subtract(new
DateTime(2007, 1, 1));
int days = tmDifference.Days;
// Now that we have the number of days,
// this number must be divisible by 14 (2 weeks)
if ((days % 14) != 0)
{
MessageBox.Show("Invalid starting period - Please try
again");
EnableForInvalidDate(false);
return;
}
else
EnableForInvalidDate(true);

// Now that we have a valid starting period,


// let's help the user and select the time period
DateTime range = e.Start.AddDays(-1);
calTimeFrame.SelectionEnd = range.AddDays(14);
}

4. Return to the form and double-click the Close button

5. Implement its Click event as follows:


 
private void btnClose_Click(object sender, EventArgs e)
{
Close();
}

6. Execute the application and try selecting a range of dates

7. Close the form and return to your programming environment

The Maximum Date Range Selection


To control the number of days you want the user to be able to select, change
the value of the MaxSelectionCount property. The user cannot select more
days than the MaxSelectionCount value but the user can select less.

Practical Learning: Set the Maximum Range

1. Return to the form and click the calendar control

2. In the Properties window, click MaxSelectionCount, type 14, and press


Enter

3. Save the form

C# 3.0 Practical Learning II 460


Windows Controls: The Picture Box
 

Introduction to the Picture Box

Description
As we have seen regularly in this and as you will see in other lessons, you can
display a picture directly on a form. Still, to give you a more comfortable
space to show a picture, the .NET Framework provides a Windows control
named PicturePox.

Getting a Picture Box


Like most controls and as we described in our introduction to control
design, to get a picture box, from the Toolbox, you can click the PictureBox

button and click the form. To programmatically get the control, you can
create a handle to the PictureBox class. Before using the control, make sure
you add it to the list of Controls of the form that will host it. Here is an
example:
using System;
using System.Windows.Forms;

public class Exercise : Form


{
private PictureBox pctBox;

public Exercise()
{
}

private void InitializeComponents()


{
pctBox = new PictureBox();
Controls.Add(pctBox);
}
}

public class Program


{
public static int Main()

C# 3.0 Practical Learning II 461


{

Application.Run(new Exercise());
return 0;
}
}

The Characteristics of a Picture Box

Introduction
As a regular visual control, after a picture box has been added to a form, it
assumes a default size (unless you dragged and drew when adding it). You
can then move or resize it using the techniques of application design we
reviewed in Lessons 3 and 4. Of course, you can also specify the location and
the size of the control programmatically. Here is an example:
using System;
using System.Drawing;
using System.Windows.Forms;

public class Exercise : Form


{
private PictureBox pctBox;

public Exercise()
{
InitializeComponents();
}

private void InitializeComponents()


{
pctBox = new PictureBox();
pctBox.Location = new Point(10, 10);
pctBox.Size = new Size(200, 150);
Controls.Add(pctBox);
}
}

public class Program


{
public static int Main()
{
Application.Run(new Exercise());
return 0;
}
}

The Border Style of a Picture Box

C# 3.0 Practical Learning II 462


By default, when you have added a picture box to a form, it appears without
borders. At run time, the form designer would show the borders so you can
conveniently move or resize it:

At run time, unless you display an object in the picture box or draw a shape
in it, the user would not know where the picture box starts and where it ends:

There is no way of knowing that the above form contains a picture box. If you
want the picture box to show its borders to the user, you can use the
BorderStyle property. We described this property in Lesson 5.

The Image of a Picture Box


As stated in the introduction, the primary purpose of a picture box is to
display a picture. To support this, the PictureBox class is equipped with a
property named Image. This property is of type Image. At design time, to
specify the picture that this control would hold, first click the picture box on
the form to select it:

 Click the triangular button in the top line:


 

C# 3.0 Practical Learning II 463


 
and click Choose Image

 Click the ellipsis button of the Image field in the Properties window

In both cases, a dialog box would come up to assist you with locating and
selecting a picture. 

To programmatically specify the picture to display, assign an Image object to


the instance of the PictureBox class. Here is an example:
using System;
using System.Drawing;
using System.Windows.Forms;

public class Exercise : Form


{
private PictureBox pctBox;

public Exercise()
{
InitializeComponents();
}

private void InitializeComponents()


{
pctBox = new PictureBox();
pctBox.Location = new Point(10, 10);
pctBox.Size = new Size(200, 150);
pctBox.Image =
Image.FromFile(@"E:\Programs\Person.bmp");
Controls.Add(pctBox);
}
}

public class Program


{
public static int Main()
{
Application.Run(new Exercise());
return 0;
}
}

C# 3.0 Practical Learning II 464


If you decide to specify the picture programmatically, make sure you provide
a valid picture or a valid path to the picture; otherwise you would receive an
error if the application cannot find the image.

The Image Location of the Image of a Picture Box


Besides the PictureBox.Image property, to assist you with specifying the
image to display, the PictureBox class provides a property named
ImageLocation. This property, which is of type String, expects either the
path to the file or the URL of the image. At design time, difference with the
Image property is that you are not asked to selected a picture but to give its
location. Therefore, to use it, in the Properties window, type the complete
path:

Remember that you can also provide a URL to the picture:

C# 3.0 Practical Learning II 465


In both cases, if you provide a bad path or a broken link, that is, if the
compiler cannot find the image, the picture box would display an X icon on
its body.

At run time, you can also specify the path or the URL to the picture by
assigning it to the PictureBox.ImageLocation property. Here is an
example:
public class Exercise : Form
{
private PictureBox pctBox;

public Exercise()
{
InitializeComponents();
}

private void InitializeComponents()


{
pctBox = new PictureBox();
pctBox.Location = new Point(10, 10);
pctBox.Size = new Size(200, 150);
pctBox.ImageLocation =
"http://www.functionx.com/cars/civic.gif";
Controls.Add(pctBox);
}
}

After assigning a string to the ImageLocation property, you can call the
PictureBox.Load() method to actually show the image. This method is
overloaded with two versions.

When accessing this property, if you use an event such as the Paint
event of the picture box or the Click event of a button, you don't have to call
the Load() method to show the picture; but it is more effective and faster.

Instead of assigning a string to the PictureBox.ImageLocation property


and calling the parameter-less PictureBox.Load() method, you can call the
other version of the method. Its syntax is:
public void Load(string url);

This version takes as argument the URL of, or the path to, the picture. Here is
an example:
public class Exercise : Form
{
private PictureBox pctBox;

public Exercise()
{
InitializeComponents();
}

C# 3.0 Practical Learning II 466


private void InitializeComponents()
{
pctBox = new PictureBox();
pctBox.Location = new Point(10, 10);
pctBox.Size = new Size(200, 150);
pctBox.Load(@"E:\Programs\person.bmp");
Controls.Add(pctBox);
}
}

After you have specified the image that the picture box would display, by
default, it is located from the top-left corner of the control. In some cases, for
example if the picture's size is lower than the control's, this would be fine and
you may not need to be concerned with that:

The picture box can show only as far as its size. If an image goes beyond the
control, its parts would be hidden. In some cases, the image may appear too
wide, too narrow, too tall, or too short for the picture box. And in some cases,
if the image's size is higher than the picture box, the control would not show
some important aspects. Therefore, in some cases, you want to resize either
the picture to fit the control, or the control to fit the picture. In some cases,
you can programmatically resize a control by changing its Size property. On
the other hand, you can scale a picture as we learned with bitmap. The
PictureBox class provides an alternative.

The Size Mode of a Picture Box


The SizeMode property of the PictureBox class allows you to specify how
the image in the control would be displayed. This property is based on the
PictureBoxSizeMode enumeration and its members are as follows:

 Normal: The picture is positioned from the top-left corner of the control
as seen in the above form

 CenterImage: The picture is positioned in the middle-center of the


control

C# 3.0 Practical Learning II 467


 

 
If you give the user the ability to resize the picture box, when this is
done, the picture would always be drawn in the middle-center of the
control

 StretchImage: The picture is resized to fit the control. Any dimension of


the picture that is lower than its equivalent on the control is increased to
match its equivalent. Any dimension of the picture that is higher than its
equivalent on the control is decreased to match its equivalent:
  
Before

After

C# 3.0 Practical Learning II 468


  
Before After


If you give the user the ability to resize the picture box, when this is
done, the picture would always resize itself to fit the size of the control

 Zoom: The image is positioned in the middle of the control but it is also
resized following a certain algorithm:

o If the image is taller than the control, the picture gets resized to
be smaller so its new width and height can fit in the control and
the ratio Bitmap.Width/Bitmap.Height ratio is respected. Here
is an example
 
Before

C# 3.0 Practical Learning II 469


After

o If the image is wider than the control, the picture gets resized to
be small enough so its new width and height can fit in the control
and the ratio Bitmap.Width/Bitmap.Height is respected. Here is
an example
 
Before After

o Imagine the image is smaller than the control:


 

C# 3.0 Practical Learning II 470


In this case, the picture's width and height would be increased
but the ratio Bitmap.Width/Bitmap.Height is kept.
To resize the picture, the compiler first finds out what dimension
is closer to its equivalent of the control:

 If the PictureBox.Height/Bitmap.Height ratio is lower


than the PictureBox.Width/Bitmap.Width ratio, then
the height of the image would first be increased to match
the height of the picture box. Then the compiler would use
the Bitmap.Width/Bitmap.Height ratio to calculate and
apply the new width of the picture. Here is an example:
 
Before

After

C# 3.0 Practical Learning II 471


 If the PictureBox.Width/Bitmap.Width ratio is lower
than the PictureBox.Height/Bitmap.Height  ratio,
then the width of the image would first be increased to
match the width of the picture box. Then compiler would
then use the Bitmap.Width/Bitmap.Height ratio to
calculate and apply the new height of the picture. Here is
an example:
 
Before After

C# 3.0 Practical Learning II 472


 If you give the user the ability to resize the picture box, every time this is
done, the compiler would use the above descriptions to resize and
position the picture inside of the control

 AutoSize: The size of the control would be changed to fit the picture:

o If the picture is smaller than the control, the size of the control
would be increased to show the whole picture
 
Before After

C# 3.0 Practical Learning II 473


o If the picture is bigger than the control, the size of the picture box
control would be decreased to fit the picture
 
Before After

C# 3.0 Practical Learning II 474


 If you had given the user the ability to resize the picture box, it cannot
be resized and the size of the picture cannot change

Windows Control: Rich Text Box


 

Introduction to the Rich Text

Description
Text is considered rich if it can display various characters or paragraphs in
different styles and features that make it more attractive than a regular ASCII
text. Such a text can have some of its sections in different colors. Its
paragraphs can have customized attributes or arranged independent of each
other. Although you can create a complete rich but static text, the common
use of a rich text is to let the user process most of the formatting.

Creating a Rich Text Control


To support a rich text, the .NET Framework provides the RichTextBox control
that is implement from the RichTextBox class. Like TextBox, the
RichTextBox class is based on TextBoxBase. Therefore, to have right text in
an application, from the Common Controls section of the Toolbox, click
RichTextBox and click the form.

To programmatically create rich text, declare a variable of type RichTextBox,


use the new operator to allocate memory for it, and add it to the Controls
collection of its parent. Here is an example:
using System;
using System.Drawing;
using System.Windows.Forms;

public class Exercise : System.Windows.Forms.Form


{
RichTextBox rchNote;

public Exercise()

C# 3.0 Practical Learning II 475


{
InitializeComponent();
}

private void InitializeComponent()


{
rchNote = new RichTextBox();

Controls.Add(rchNote);
}
}

public class Program


{
static int Main()
{
System.Windows.Forms.Application.Run(new Exercise());
return 0;
}
}
Practical Learning: Starting a Rich Text Application
1. Start Microsoft Visual C# and create a new Windows Application named
Notice1

2. In the Solution Explorer, right-click Form1.cs and click Rename

3. Type Editor.cs as the new name of the form and press Enter

4. From the Dialogs section of the Toolbox, click OpenFileDialog and


click the form

5. In the Properties window, click DefaultExt and type rtf

6. Click (Name) and type dlgOpen

7. Click Filter and type Rich Text Format (*.rtf)|*.rtf|Text File


(*.txt)|*.txt|All Files|

8. From the Dialogs section of the Toolbox, click SaveFileDialog and


click the form

9. In the Properties window, click DefaultExt and type rtf

10. Click (Name) and type dlgSave

11. Click Filter and type Rich Text Format (*.rtf)|*.rtf|Text File
(*.txt)|*.txt|All Files|

12. From the Common Controls section of the Toolbox, click RichTextBox
and click the form

13. From the Menus & Toolbars section of the Toolbox, click MenuStrip and

C# 3.0 Practical Learning II 476


click the form

14. On the form, click Type Here, type File and press Enter

15. Under File, click Type Here, type New and press Enter

16. On the right side of File, click Type Here, type Edit and press Enter

17. Under Edit, click Type Here, type New and press Enter

18. In the same way, complete the menu strip with the following items:
 

C# 3.0 Practical Learning II 477


19. Double-click an unoccupied area of the form and change the file 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;

namespace Notice1
{
public partial class Editor : Form
{
string CurrentFileName;

public Editor()
{
InitializeComponent();
}

private void Editor_Load(object sender, EventArgs e)


{
CurrentFileName = "<Not Allowed>";
rchEditor.Modified = false;
}
}
}

20. Return to the form and click the rich text control

21. In the Properties window, change the its properties as follows:


Name: rchEditor
AcceptsTab: True
Font: Times New Roman, 12pt
Dock: Fill

C# 3.0 Practical Learning II 478


ScrollBars: Vertical

22. On the form, click Edit and double-click Undo

23. Implement the event as follows:


 
private void mnuEditUndo_Click(object sender, EventArgs e)
{
rchEditor.Undo();
}

24. Return to the form

25. On the form, click Edit and double-click Redo

26. Implement the event as follows:


 
private void mnuEditRedo_Click(object sender, EventArgs e)
{
rchEditor.Redo();
}

27. Return to the form

28. On the form, click Edit and double-click Cut

29. Implement the event as follows:


 
private void mnuEditCut_Click(object sender, EventArgs e)
{
rchEditor.Cut();
}

30. Return to the form

31. On the form, click Edit and double-click Copy

32. Implement the event as follows:


 
private void mnuEditCopy_Click(object sender, EventArgs e)
{
rchEditor.Copy();
}

33. Return to the form

34. On the form, click Edit and double-click Paste

35. Implement the event as follows:


 
private void mnuEditPaste_Click(object sender, EventArgs e)

C# 3.0 Practical Learning II 479


{
rchEditor.Paste();
}

36. Return to the form

37. On the form, click Edit and double-click Select All

38. Implement the event as follows:


 
private void mnuSelectAll_Click(object sender, EventArgs e)
{
rchEditor.SelectAll();
}

39. Return to the form

40. Click Format and double-click Word Wrap

41. Implement the event as follows:


 
private void mnuFormatWordWrap_Click(object sender, EventArgs e)
{
rchEditor.WordWrap = true;
}

42. Save all

The Text of a Rich Text Box


 

Introduction
Like the other graphical Windows controls, the right text box uses the common
characteristics such as the location, the size, the minimum size, the maximum
size, the anchor, the docking, the font, the ability to be visible or hidden, the
ability to be enabled or disabled, and the border style. Like the TextBox control,
the rich text control inherits various characteristics from the TextBoxBase
class, including the Text property, the Lines collection, the read-only attribute,
the ability to select and manipulate text. The rich text box also shares various
characteristics with the multi-line text box such as the Multiline property, the
scroll bars, the word wrap, the ability to accept the Tab and the Enter keys.
Here is an example:
private void InitializeComponent()
{
rchNote = new RichTextBox();
rchNote.Size = new Size(Width, Height);
rchNote.Multiline = true;
rchNote.ScrollBars = RichTextBoxScrollBars.Both;

C# 3.0 Practical Learning II 480


rchNote.AcceptsTab = true;
rchNote.Font = new Font("Verdana", 10.0F);
string[] strLines =
{
"LeavingSydney",
"When we decided to leave, we knew we were " +
"making a hard decision. We had spent so much " +
"time this had become our new home. A few " +
"weeks or months before, we wanted to make " +
"Sydney our newly found settlement, a " +
"permanent place we could proudly call ours. " +
"It appeared that, unpredictably, fate had " +
"decided otherwise.",
"Author: Arthur D. Pale",
"Title: Stories Of My Life"
};
rchNote.Lines = strLines;

Controls.Add(rchNote);
}
}

Saving the Contents of a Rich Text Document


After creating and formatting a rich text document, you may want to save it for
later use. To support this, the RichTextBox class provides a method named
named SaveFile that is overloaded with three versions. One of the versions
uses the following syntax:
public void SaveFile(string path);

This method takes as argument the name or path to a file. It will save the file
as RTF. If you want the user to save a file that is either RTF, ASCII, or another
format, to specify the desired format, you can use the following version of the
method:
public void SaveFile(string path, RichTextBoxStreamType
fileType);

As seen in the first version, the first argument is the name or path of the file.
The second argument allows you to specify the type of file that is being saved,
which could be a normal ASCII text. This argument is of type
RichTextBoxStreamType, which is an enumeration. The members of the
RichTextBoxStreamType enumeration are PlainText, RichNoOleObjs,
RichText, TextTextOleObjs, or TextTextOleObjs.

Instead of directly using the name of the file, you can create it as a stream. In
this case, the RichTextBox class provides the following version of the
SaveFile() method:

public void SaveFile(Stream data, RichTextBoxStreamType


fileType);

C# 3.0 Practical Learning II 481


This version expects a Stream-based object such as a FileStream variable.

Opening a Rich Text File


To assist you with opening a rich text file, the RichTextBox class is equipped
with the LoadFile() method overloaded with three versions. The simplest
versions has the following syntax:
public void LoadFile(string path);

This method takes as argument the name or path to a file. The file must be in
RTF format. If it is not, the file will not be opened and the compiler would
throw an IOException exception. If you want to give the user the ability to
open different types of files, you should use the following version of the
LoadFile() method:

public void LoadFile(string path, RichTextBoxStreamType


fileType);

The first argument is the same as a the single argument of the first version.
The second argument allows you to specify the type of file that is being
opened, which could be a normal ASCII text. This argument is of type
RichTextBoxStreamType.

Instead of directly using the name of the file, you can create it as a stream. In
this case, the RichTextBox class provides the following version of the
LoadFile() method:

public void LoadFile(Stream data, RichTextBoxStreamType


fileType);

This version expects a Stream-based object such as a FileStream variable.

Practical Learning: Opening a Rich Text File


1. On the form, click File and double-click New

2. Implement the event as follows:


 
private void mnuFileNew_Click(object sender, EventArgs e)
{
// This is the question the user will have to answer
DialogResult answer = MessageBox.Show(
"The document has changed. Do you want to
save it?" +
"\nClick\n" +
"Yes:\tTo save the document and create a new
one.\n" +
"No:\tNot to save the document but create a
new one.\n" +
"Cancel:\tNot to do anything",
"Editor - Saving a File",

C# 3.0 Practical Learning II 482


MessageBoxButtons.YesNoCancel,
MessageBoxIcon.Question);

// When the user clicks File -> New to start a new document,
// before creating a new document,
// find out if the document is "dirty" ask
// the user whether to save or not
if (rchEditor.Modified == true)
{
// Present the message box to the user who
// will decide whether to save
if (answer == DialogResult.Yes)
{
// If the user answers Yes
// Find out if the current document has never been
saved
if (CurrentFileName == "<Not Allowed>")
{
// If it has never been saved,
// then display the Save dialog box
if (dlgSave.ShowDialog() == DialogResult.OK)
{
// Save the file
rchEditor.SaveFile(dlgSave.FileName);
// Change the current file name to something
not allowed
CurrentFileName = "<Not Allowed>";
// Display Untitled name of the
// current file on the title bar
Text = "Parasol - Untitled";
// Since the document has been saved and the
user wants
// to create a new one, empty the control
rchEditor.Clear();
// Update the Modified attribute
rchEditor.Modified = false;
}
else // the user had clicked Cancel, don't do
anything
return;
}
else // If the document was saved before, then
simply update it
{
rchEditor.SaveFile(CurrentFileName);
// Change the current file name to something not
allowed
CurrentFileName = "<Not Allowed>";
// Display Untitled name of the current file on
the title bar
Text = "Parasol - Untitled";
rchEditor.Clear();
// Update the Modified attribute
rchEditor.Modified = false;
}
}

C# 3.0 Practical Learning II 483


else if (answer == DialogResult.No)
{
// If the user answered No,
// then simply start a new document
rchEditor.Clear();
// Change the current file name to something not
allowed
CurrentFileName = "<Not Allowed>";
// Display Untitled name of the current file on the
title bar
Text = "Parasol - Untitled";
// Update the Modified attribute
rchEditor.Modified = false;
}
else // If the user clicked Cancel, don't do anything
return;
}
else // If the document was not modified, then start a new
one
{
// If the user answered No,
// then simply start a new document
rchEditor.Clear();
// Change the current file name to something not allowed
CurrentFileName = "<Not Allowed>";
// Display Untitled name of the current file on
the title bar
Text = "Parasol - Untitled";
// Update the Modified attribute
rchEditor.Modified = false;
}
}

3. Return to the form

4. On the form, click File and double-click Open

5. Implement the event as follows:


 
private void mnuFileOpen_Click(object sender, EventArgs e)
{
// Find out if there was a document and if the document was
"dirty"
if(rchEditor.Modified == true)
{
// Here is the question the user will answer
DialogResult answer = MessageBox.Show(
"The document has changed. Do you want
to save it?" +
"\nClick\n" +
"Yes:\tTo save the document and open a
new one.\n" +
"No:\tNot to save the document but open a
new one.\n" +
"Cancel:\tNot to do anything",

C# 3.0 Practical Learning II 484


"Editor - Opening a File",
MessageBoxButtons.YesNoCancel,
MessageBoxIcon.Question);

// Find out if the user wants to save the current


document
if (answer == DialogResult.Yes)
{
// Find out if this is a new document
if (CurrentFileName == "<Not Allowed>")
{
// Since the user wants to save the document,
// display the Save dialog box
if (dlgSave.ShowDialog() ==
DialogResult.OK)
{
// Save the file

rchEditor.SaveFile(dlgSave.FileName);
}
else
return;
}
else
{
// This was not a new document,
// so, simply save it
rchEditor.SaveFile(CurrentFileName);
}
}
else if (answer == DialogResult.No)
{
// If the user answered No to the question,
don't save
// Simply open the file
if (dlgOpen.ShowDialog() == DialogResult.OK)
{
// Open the new document after
// letting the user select it
rchEditor.LoadFile(dlgOpen.FileName);
// Change the file name of our archives
CurrentFileName = dlgOpen.FileName;
// Get the name of the file that the
user selected
FileInfo fleParasol = new
FileInfo(dlgOpen.FileName);
Text = "Parasol - " + fleParasol.Name;
rchEditor.Modified = false;
}
else
return;
}
else
return;
}
else

C# 3.0 Practical Learning II 485


{
if (dlgOpen.ShowDialog() == DialogResult.OK)
{
// Open the new document after letting the
user select it
rchEditor.LoadFile(dlgOpen.FileName);
// Change the file name of our archives
CurrentFileName = dlgOpen.FileName;
// Get the name of the file that the user
selected
FileInfo fleParasol = new
FileInfo(dlgOpen.FileName);
Text = "Parasol - " + fleParasol.Name;
rchEditor.Modified = false;
}
}
}

6. Return to the form

7. On the form, click File and double-click Save

8. Implement the event as follows:


 
private void mnuFileSave_Click(object sender, EventArgs e)
{
// Find out if the current document has never been saved
// but is not empty
if( (rchEditor.Modified == true) &&
(CurrentFileName == "<Not Allowed>") )
{
// Since the document is dirty, display the Save As
dialog box
if (dlgSave.ShowDialog() == DialogResult.OK)
{
// Retrieve the new name file and display
// the file in the rich edit control
rchEditor.SaveFile(dlgSave.FileName);
// Change/Update the global and complete name of the
file,
// including its path
CurrentFileName = dlgSave.FileName;
// Extract the name of the file
FileInfo fleParasol = new
FileInfo(dlgSave.FileName);
// Display the name of the current file on the title
bar
Text = "Parasol - " + fleParasol.Name;
}
else
return;
}
else
{
// It appears that this document already had a

C# 3.0 Practical Learning II 486


name
// but the document was previously modified
// Therefore, simply save it internally
rchEditor.SaveFile(CurrentFileName);
}
}

9. Return to the form

10. On the form, click File and double-click Save As

11. Implement the event as follows:


 
private void mnuFileSaveAs_Click(object sender, EventArgs e)
{
if (dlgSave.ShowDialog() == DialogResult.OK)
{
rchEditor.SaveFile(dlgSave.FileName);
// Change the file name of our archives
CurrentFileName = dlgSave.FileName;
// Get the name of the file that the user
selected
FileInfo fleParasol = new
FileInfo(dlgSave.FileName);
Text = "Parasol - " + fleParasol.Name;
rchEditor.Modified = false;
}
}

12. Return to the form

13. On the form, click File and double-click Exit

14. Implement the event as follows:


 
private void mnuFileExit_Click(object sender, EventArgs e)
{
// Is the document dirty?
if (rchEditor.Modified == true)
{
// Since the document is dirty,
// find out if the user wants to save it
DialogResult answer = MessageBox.Show(
"The document has changed. Do you want to
save it?" +
"\nClick\n" +
"Yes:\tTo save the document and close the
application.\n" +
"No:\tNot to save the document but close the
application.\n" +
"Cancel:\tNot to do anything",
"Parasol - Saving a File",
MessageBoxButtons.YesNoCancel,
MessageBoxIcon.Question);

C# 3.0 Practical Learning II 487


// If the user wants to save it
if (answer == DialogResult.Yes)
{
// Behave as if the user had clicked File .
Save
mnuFileSave_Click(sender, e);
Close();
}
else if (answer == DialogResult.No)
{
// If the user doesn't want to save the
document
Close();
}
// The user cancelled the action: do nothing
else
return;

}
else // There is no action to take
Close();
}

15. Return to the form

Rich Text Formatting


 

Formatting Text
We saw that you could change the general font of a text box and you can
change the color of the characters. If you do this on a text box, all of the
characters are changed to the same font and the same color. One of the
extended properties of a rich text box over a regular text box is the ability to
change the font and/ the color of individual characters, words, or paragraphs
and the change applies only to the desired characters.

Before changing a character or a word, you must first select it. To change the
font of the text that is selected on the control, the selected text is identified
with the SelectionFont property. To change the color of the text that is
selected, the selected text is identified with the SelectionColor property.

To assist you with this, you can use the Font dialog box. After selecting the
character or word, you can transfer their attributes to the Font dialog box
before displaying it. After using the dialog box, if the user clicks OK, you can
retrieve the font and color characteristics then apply them to the selected
character or text.

Practical Learning: Formatting Text

C# 3.0 Practical Learning II 488


1. From the Dialogs section of the Toolbox, click FontDialog and click
the form

2. Click (Name) and type dlgFont

3. Double-click ShowColor to set its value to True

4. On the form, click Format and double-click Font

5. Implement the event as follows:


 
private void mnuFormatFont_Click(object sender, EventArgs e)
{
// Get the characteristics of the selected text
// Apply them to the Font dialog box
dlgFont.Font = rchEditor.SelectionFont;
dlgFont.Color = rchEditor.SelectionColor;

if (dlgFont.ShowDialog() == DialogResult.OK)
{
// Display the Font dialog box
// If the user clicks OK, get the
characteristics of the font
// Apply them to the selected text of the Rich
Edit control
rchEditor.SelectionFont = dlgFont.Font;
rchEditor.SelectionColor = dlgFont.Color;
}
}

6. Return to the form

The Paragraph Alignment


For a text-based control, a paragraph is a series of words that start with a letter
or empty space until the flow of text is interrupted, which is usually made with
a carriage return, or the end of the document. By itself, the paragraph controls
its alignment and such details as Tab measurements or indentation. To set or
change the properties of a paragraph, you must first select it. To select a
paragraph, you don't need to formally select it or any portion of its text. As long
as the cursor is positioned inside of the paragraph, any paragraph attribute you
set or change would apply to the whole paragraph. To manipulate more than
one paragraph at the same time, you or your user must select them. The
paragraphs do not need to be wholly selected. As long as a section is selected
on it, a paragraph is considered selected.

The most common property of a paragraph is its alignment, which states


whether the paragraph is positioned to the left, the center, or the right. This
characteristic is controlled by the SelectionAlignment property. The
SelectionAlignment property is based on the HorizontalAlignment
enumeration whose members are Left, Center, and Right. Because this

C# 3.0 Practical Learning II 489


property is applied on (individual) paragraphs, it is not available at design time.

To change the alignment at run time, assign the desired value to the
SelectionAlignment property. In the following example, the alignment of the
selected paragraph is set in response to the user clicking a button:
private void button1_Click(object sender, EventArgs e)
{
richTextBox1.SelectionAlignment =
HorizontalAlignment.Center;
}
Practical Learning: Aligning a Paragraph
1. On the form, click Format and double-click Paragraph Align Left

2. Implement the event as follows:


 
private void mnuFormatAlignLeft_Click(object sender, EventArgs
e)
{
rchEditor.SelectionAlignment =
HorizontalAlignment.Left;
}

3. Return to the form, click Format and double-click Paragraph Align Center

4. Implement the event as follows:


 
private void mnuFormatAlignCenter_Click(object sender, EventArgs
e)
{
rchEditor.SelectionAlignment =
HorizontalAlignment.Center;
}

5. Return to the form, click Format and double-click Paragraph Align Right

6. Implement the event as follows:


 
private void mnuFormatAlignRight_Click(object sender, EventArgs
e)
{
rchEditor.SelectionAlignment =
HorizontalAlignment.Right;
}

7. Return to the form

The Indentation of a Paragraph


Indentation is the number of empty characters that separate a paragraph edge

C# 3.0 Practical Learning II 490


from one of the borders of the rich text control. Indentation refers to the left
side or the right side of a paragraph. Based on this, left indentation refers to
the number of empty characters from the left border of the rich text control to
the left edge of a paragraph. The rich text control provides indentation through
various properties.

To support indentation from the left side of a paragraph, the RichTextBox


class is equipped with a property named SelectionIndent property. To indent
from the right side, the RichTextBox is equipped with the
SelectionRightIndent property.

Practical Learning: Indenting a Paragraph


1. On the form, click Format and double-click Left Indent

2. Implement the event as follows:


 
private void mnuFormatLeftIndent_Click(object sender, EventArgs
e)
{
rchEditor.SelectionIndent += 10;
}

3. Return to the form, click Format and double-click Right Indent

4. Implement the event as follows:


 
private void mnuFormatRightIndent_Click(object sender, EventArgs
e)
{
rchEditor.SelectionRightIndent += 10;
}

5. Return to the form

A Bulleted Paragraph
Instead of just a regular section made only of text, you can create an
unordered list of lines or paragraphs in your document. To support this, the
RichTextBox class is equipped with a Boolean property named
SelectionBullet. If you set this property to false on a paragraph, the
paragraph would start with a bullet. If you apply this property to more than one
consecutive paragraph, each would start with a bullet.

Practical Learning: Using a Rich Text Control


1. On the form, click Format and double-click each button and implement
their Click events as follows:
 

C# 3.0 Practical Learning II 491


private void mnuFormatBulletList_Click(object sender, EventArgs
e)
{
rchEditor.SelectionBullet = true;
}

2. Execute the application and test the controls

Close the form and return to your programming environment

Accessories for Control Design: The


Table Layout Panel
 

Introduction
During your application design, if you have a group of controls that you want
to align either horizontally or vertically, you can use the flow layout panel.
You can use different rows and columns of flow layout panels to align the
controls. If you do this, you would then have to align the flow layout panels
also to make sure their controls are aligned. In reality, the flow layout panel is
a valuable accessory for control design but it may not effectively align
different types of controls. To assist with another type of problem, you can
use the table layout panel.

The table layout panel is represented in the .NET Framework by the


TableLayoutPanel class and in the Toolbox by the TableLayoutPanel
control. To use it at design time, from the Toolbox, click the TableLayoutPanel
button and click the form. When it has been added, it presents a dotted table
made of four cells:

C# 3.0 Practical Learning II 492


To use the table layout panel as a design object, you can click a control from
the Toolbox and click a cell in the table. The control would be added to that
cell. To add another control to the application, you can click it from the
Toolbox and click another cell:

Characteristics of a Table Layout


You cannot add a control to a cell if that cell contains a control already. If you
want to add more controls than the cells in the table layout panel, you can
add new cells. To do this, first select the table layout panel from the form:

 To add a new column, under the Properties window, you can click Add
Column

 To add a row, under the Properties window, you can click Add Row

 To add more than one column or more than one row, in the Properties
window, click Columns or Rows and click its ellipsis button. This would
open the Column and Row Style dialog box
 

C# 3.0 Practical Learning II 493


 
To add a column, in the Show combo box, select Columns and click Add.
To add a row, in the Show combo box, select Rows and click Add. After
using the dialog box, you can click OK

Besides the ability to align the controls, the table layout panel provides
various aesthetic characteristics, such as the background color of the table,
various styles for the dividing lines of the cells, etc.

The Characteristics of a Button


 

The Caption of a Button


For a user, the most important aspects of a button are the message it
displays and the action it performs. The text the button displays allows the
user to know what the button is used for. This is represented by the Text

C# 3.0 Practical Learning II 494


property. The most popular strings that the buttons display are OK and
Cancel. The OK caption is set for a form or a dialog box that informs the user
of an error, an intermediary situation, or an acknowledgement of an action
that was performed on the dialog that hosts the button. The Cancel caption is
useful on a button whose main parent (the form or the dialog box) would ask
a question or request a follow-up action from the user. Whenever a dialog
box allows the user to dismiss it without continuing the action, you should
provide a button with a Cancel caption.

After adding a button to a form (by design or with code), you can change its
caption with code by assigning the desired string to the Text property. For
example, you can change the caption of a button as follows:
button1.Text = "Let it Go!";

After specifying the Text of a button, by default, it's positioned in the middle
center of the button:

The position of the text of a button is controlled through the TextAlign


property which is a value of the ContentAlignment enumerator. The possible
values are:

TopLeft TopCenter TopRight

MiddleLeft MiddleCenter MiddleRight

BottomLeft BottomCenter BottomRight

Here is an example:
public class Exercise : System.Windows.Forms.Form
{
Button btnResume;

public Exercise()

C# 3.0 Practical Learning II 495


{
InitializeComponent();
}

private void InitializeComponent()


{
btnResume = new Button();
btnResume.Text = "Resume";
btnResume.Location = new Point(32, 20);
btnResume.Size = new System.Drawing.Size(120, 48);
btnResume.TextAlign = ContentAlignment.BottomCenter;

Controls.Add(btnResume);
}
}

Practical Learning: Using the Buttons

1. Access each tab page and add a button to it

2. Add a button to the form and under the tab control

3. Complete the design of the form as follows:


 

Control Text Name

Button Calculate btnCalcFactorial

C# 3.0 Practical Learning II 496


Button Close btnClose

Control Text Name

Button Calculate btnCalcPermutation

Control Text Name

Button Calculate btnCalcCombination

4. Access the Factorial tab page and double-click its Calculate button

C# 3.0 Practical Learning II 497


5. Implement the event as follows:
 
private void btnCalcFactorial_Click(object sender, EventArgs e)
{
long number = 0;
long result;

try
{
number = long.Parse(txtFactNumber.Text);
result = Algebra.Factorial(number);
txtFactorial.Text = result.ToString();
}
catch (FormatException)
{
MessageBox.Show("Invalid Number");
}
}

6. Return to the form

7. Access the Permutation tab page and double-click its Calculate button

8. Implement the event as follows:


 
private void btnCalcPermutation_Click(object sender, EventArgs
e)
{
long n = 0, r = 0;
long result;

try
{
n = long.Parse(txtPermutationN.Text);
}
catch (FormatException)
{
MessageBox.Show("Invalid Number");
}

try
{
r = long.Parse(txtPermutationR.Text);
result = Algebra.Permutation(n, r);
txtPermutation.Text = result.ToString();
}
catch (FormatException)
{
MessageBox.Show("Invalid Number");
}
}

9. Return to the form

C# 3.0 Practical Learning II 498


10. Access the Combination tab page and double-click its Calculate button

11. Implement the event as follows:


 
private void btnCalcCombination_Click(object sender, EventArgs
e)
{
long n = 0, r = 0;
long result;

try
{
n = long.Parse(txtCombinationN.Text);
}
catch (FormatException)
{
MessageBox.Show("Invalid Number");
}

try
{
r = long.Parse(txtCombinationR.Text);
result = Algebra.Combinatorial(n, r);
txtCombination.Text = result.ToString();
}
catch (FormatException)
{
MessageBox.Show("Invalid Number");
}
}

12. Return to the form and double-click the Close button

13. Implement the event as follows:


 
private void btnClose_Click(object sender, EventArgs e)
{
Close();
}

14. Execute the application to test the calculations


 

C# 3.0 Practical Learning II 499


15. Close the form and return to your programming environment

The Image on a Button


Besides, or instead, of a caption, a button can display a picture on top. If you
want a button to display a bitmap, you should first create, design, or have a

C# 3.0 Practical Learning II 500


picture. Then, in the Properties window, use the Image field to select a
bitmap or an icon. You can also programmatically assign an Image object to
the Image property. Here is an example:
private void InitializeComponent()
{
btnResume = new Button();
btnResume.Text = "Resume";
btnResume.Location = new Point(32, 20);
btnResume.Size = new System.Drawing.Size(120, 48);
btnResume.Image =
Image.FromFile(@"E:\Programs\neutral.gif");

Controls.Add(btnResume);
}

This would produce:

By default, both the caption and the image display ion the middle-center of
the button. To make them distinct and allow the user to see both, you can
design a bitmap that has both and assign that bitmap as the image of the
button. Alternatively, you can use a separate string and a separate picture.
Fortunately, each can have its own alignment. We already saw how to control
the alignment of the caption.

Besides displaying an image, the Button class is equipped with the


ImageAlign property that allows you to specify the alignment of the image.
The ImageAlign property is inherited from the ButtonBase class. The
ButtonBase.ImageAlign property is based on the ContentAlignment
enumeration that we are already familiar with. Here is an example:
private void InitializeComponent()
{
btnResume = new Button();
btnResume.Location = new Point(32, 20);
btnResume.Size = new System.Drawing.Size(120, 48);
btnResume.Text = "Resume";
btnResume.TextAlign = ContentAlignment.BottomCenter;
btnResume.Image =
Image.FromFile(@"E:\Programs\neutral.gif");
btnResume.ImageAlign = ContentAlignment.TopCenter;

Controls.Add(btnResume);
}

This would produce:

C# 3.0 Practical Learning II 501


Instead of using the Image property, you can first create an image list and
add some pictures to it. Then, using the ImageList property, assign it to the
button. Use the ImageIndex property to specify what picture would be
displayed on the button.

The Flat Style of a Button


A regular button displays with raised borders as originally set by the operating
system. To give your button a fancy look and behavior, you can use the
FlatStyle property. The FlatStyle property is based on an enumeration of
the same name. It provides 4 values that are:

 Flat: The button appears flat. When the mouse is over it, it becomes
highlighted

 Popup: The button appears flat. When the mouse is over it, the borders
of the button are raised

 Standard: The button appears and behave like all regular buttons you
have seen

 System: The appearance of the button depends on the operating system

Obviously the most important and the most intuitive event of a button occurs
when clicked. This event is of type EventArgs, which indicates that it doesn't
provide nor does it need any formal details about what is going on. To launch
this event, you can double-click the button on the form. To create this event
programmatically, first implement the method that would carry its
assignment, then increment-add (with the += operator) it to the Click
property of the button by assigning it the EventHandler constructor.

The Result of a Dialog Box


After the user has used a form or dialog box, to close it, the user would click
a button. When the user does this, you must find out what button was
clicked. Although there are various ways you can get this information, to
assist you, the .NET Framework provides a convenient mechanism through an
enumeration named DialogResult.

When creating a form or a dialog box, after adding a button, in the Properties
window, click DialogResult and select on the values:

C# 3.0 Practical Learning II 502


Except for None, by default, it does not matter what value you select but, you
should follow Windows standard to select the right value.

After specifying the returned value of a button, access the properties of the
form or dialog box:

 If you had selected OK as the DialogResult value of a button, you


should select the name of that button for the AcceptButton property of
the form

 If you had selected Cancel as the DialogResult value of a button, you


should select the name of that button for the CancelButton property of
the form

After configuring the DialogResult of the button(s), when the user clicks
one of the buttons to close the form or dialog box, you can get the value of
the Form.ShowDialog() method which returns one of the values of the
DialogResult enumeration.

Applications:
Algebra

Simple Interest

The Browse For Folder Dialog Box


 

C# 3.0 Practical Learning II 503


 

Description
The Save and Open dialog boxes allow a user to save or open files only.
Microsoft Windows provides a dialog box specially made so that a user can
select a folder if an application needs one for any reason a programmers
judges necessary. This dialog box appears as follows:

When this dialog box comes up, it displays the Desktop folder as the parent
and all the other folders can be located from it. To use it, the user can click
one of the folders or drives and click OK. If the desired folder is not seen but
is available, the user can expand the existing folders and drives, click the
desired folder, and click OK. If the necessary folder is not available at all, the
user can first select an existing folder or drive, click the Make New Folder
button, type a name for the new folder, and click OK.

Besides the folders, the Browse For Folder dialog box also allows the user to
navigate to folders or directories of the network.

Creating a Browse For Folder Dialog Box

C# 3.0 Practical Learning II 504


The Browse For Folder dialog box is made available through the
FolderBrowserDialog class that is derived from the CommonDialog class.
To provide its functionality to your application, at design time, from the
Toolbox, click FolderBrowserDialog and click the form.

To programmatically initiate this dialog box, you can declare a pointer to


FolderBrowserDialog, use the new operator to allocate memory for it by
calling its default constructor.

To display the Browse For Folder dialog box, call its ShowDialog() method.
Here is an example:
using System;
using System.Collections.Generic;
using System.ComponentModel;

using System.Data;

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

namespace WindowsApplication2
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

private void label1_Click(object sender, EventArgs e)


{
folderBrowserDialog1.ShowDialog();
}
}
}

This would produce:

C# 3.0 Practical Learning II 505


 

Characteristics of the Browse For


Folder Dialog Box
 

The Description
By default, and as seen on the above screenshot, the Browse For Folder
dialog box doesn't indicate what it is used for. This is because it is left to you
to let the user know what you expect. To provide this information, the Browse
For Folder dialog box is equipped with a label that can be made visible or
not. It is available through the Description property. If you provide a string
for this property, it would display under the title bar but above the tree view
of the dialog box. If you add the FolderBrowserDialog control to the form,
you can type a string in the Description field in the Properties window.

You can also programmatically assign a string to the FolderBrowserDialog


object. Here is an example:

C# 3.0 Practical Learning II 506


public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

private void label1_Click(object sender, EventArgs e)


{
folderBrowserDialog1.Description =
"Select the directory where your " +
"future configurations will be installed";
folderBrowserDialog1.ShowDialog();
}
}

This would produce:

The Root Folder


As you can see from this screenshot, when the dialog box comes up, it selects
the Desktop, by default, as the parent folder. If you want, you can specify a
different default folder to be selected. This information is carried by the
RootFolder property. The RootFolder value must be a member of the
SpecialFolder enumerator of the Environment class. For example, to
select My Documents, you would type the following:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

C# 3.0 Practical Learning II 507


private void label1_Click(object sender, EventArgs e)
{
folderBrowserDialog1.Description =
"Select the directory where your " +
"future configurations will be installed";
folderBrowserDialog1.RootFolder =
Environment.SpecialFolder.Personal;
folderBrowserDialog1.ShowDialog();
}
}

This would produce:

The Selected Path


Since there is only a limited number of folders of the SpecialFolder
enumerator, you may want to specify a different folder. The advantage of the
SpecialFolder option is that it is likely to be found on the user's computer.
If you know for sure that a certain folder exists on the computer and you
would rather select that folder, you can provide its complete path to the
SelectedPath property. Here is an example:

public partial class Form1 : Form


{
public Form1()
{
InitializeComponent();
}

private void label1_Click(object sender, EventArgs e)


{
folderBrowserDialog1.Description =
"Select the directory where your future " +
"configurations will be installed";

C# 3.0 Practical Learning II 508


folderBrowserDialog1.SelectedPath =
@"C:\Programs\Corporate";
folderBrowserDialog1.ShowDialog();
}
}

This would produce;

You should not specify both the RootFolder and the SelectedPath
properties on the same FolderBrowserDialog control.

After the user has used the Browse For Folder dialog box, has selected a
folder, and clicked OK, to find out what folder the user selected, get the value
of the SelectedPath property.

The Make New Folder Button


After using the Browse For Folder dialog box, the user may select a folder and
click OK. Imagine you are creating a commercial application, you can't
possibly know the content of every customer's computer. This means that
there is a possibility that the user would not find the desired folder. One
solution you can use is to give users the ability to create a new folder. This
option is available by default. If you want to prevent the user from creating a
new folder, hide the Make New Folder button. To do this, assign a false value
to the ShowNewFolderButton Boolean property. You can do this in the
Properties window at design time or programmatically as follows:
public partial class Form1 : Form
{

C# 3.0 Practical Learning II 509


public Form1()
{
InitializeComponent();
}

private void label1_Click(object sender, EventArgs e)


{
folderBrowserDialog1.Description =
"Select the directory where your future " +
"configurations will be installed";
folderBrowserDialog1.SelectedPath =
@"C:\Programs\Corporate";
folderBrowserDialog1.ShowNewFolderButton = false;
folderBrowserDialog1.ShowDialog();
}
}

This would produce:

You can also check the value of the ShowNewFolderButton property to find
out whether the dialog box is equipped with a Make New Folder button.

C# 3.0 Practical Learning II 510


Application Menus: Contextual
Menus
 

Introduction
In our introduction to the main menu, we saw that, to access it, the user
clicks one of its categories. A contextual menu is one that appears when the
user right-clicks an area of an application or form. In most applications,
when the user right-clicks a title bar, the operating system is configured to
display a system menu. Here is an example:

A menu is considered, or qualifies as, popup if, or because, it can appear


anywhere on the form as the programmer wishes. Such a menu is also
referred to as context-sensitive or contextual because its appearance and
behavior depend on where it displays on the form or on a particular control.
The person who creates the application decides if or where the contextual
menu would appear. Because this characteristic is up to the programmer, the
same application can display different types of popup menus depending on
where the user right-clicks. Here are examples:

C# 3.0 Practical Learning II 511


The first difference between a main menu and a popup menu is that a popup
menu appears as one category or one list of items and not like a group of
categories of menus like a main menu. Secondly, while a main menu by
default is positioned on the top section of a form, a popup menu doesn't have
a specific location on the form.

Creating a Contextual Menu

C# 3.0 Practical Learning II 512


To support the creation and management of contextual menus, the .NET
Framework provides the ContextMenuStrip class. This class is derived from
ToolStripDropDownMenu, which itself is based on the ToolStripDropDown
class. The ToolStripDropDown class is derived from ToolStrip.

To visually create a contextual menu, in the Menus & Toolbars section of the
Toolbox, click the ContextMenuStrip button and click the form. Once
you have a ContextMenuStrip object, you can create its menu items. To do
this, as mentioned for the MenuStrip, you can click the first Type Here line,
type a string, press Enter, and continue creating the other menu items in the
same way.

Unlike a main menu, a popup menu provides a single list of items. If you
want different popup menus for your form, you have two options. You can
create various popup menus or programmatically change your single popup
menu in response to something or some action on your form.

To programmatically create a contextual menu, start by declaring a handle to


ContextMenuStrip. Here is an example:

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

public class Exercise : System.Windows.Forms.Form


{
public Exercise()
{
InitializeComponent();
}

void InitializeComponent()
{
System.Windows.Forms.ContextMenuStrip context =
new System.Windows.Forms.ContextMenuStrip();
}
}

public class Program


{
static int Main()
{
System.Windows.Forms.Application.Run(new Exercise());
return 0;
}
}

To assist you with each item of a contextual menu, ToolStrip, the ancestor
to the ContextMenuStrip class, is equipped with a property named Items.
This property is of type ToolStripItemCollection, which is a collection-
based class. The ToolStripItemCollection class implements the IList,
the ICollection, and the IEnumerable interfaces.

C# 3.0 Practical Learning II 513


To create one or more menu items, you can use the various techniques we
reviewed for the main menu. Here are examples:
void InitializeComponent()
{
System.Windows.Forms.ContextMenuStrip context =
new System.Windows.Forms.ContextMenuStrip();

ToolStripMenuItem mnuCut = new ToolStripMenuItem("Cut");

ToolStripMenuItem[] mnuEdit =
{
new ToolStripMenuItem("Copy"),
new ToolStripMenuItem("Paste")
};
}

After creating a menu item, to add it to the contextual menu, you can call the
ToolStripItemCollection.Add() method. To add an array of items, you
can call the create ToolStripItemCollection.AddRange() method. Here
are examples:
void InitializeComponent()
{
System.Windows.Forms.ContextMenuStrip context =
new System.Windows.Forms.ContextMenuStrip();

ToolStripMenuItem mnuCut = new ToolStripMenuItem("Cut");


ToolStripMenuItem[] mnuEdit =
{
new ToolStripMenuItem("Copy"),
new ToolStripMenuItem("Paste")
};

context.Items.Add(mnuCut);
context.Items.AddRange(mnuEdit);
}

Practical Learning: Introducing Contextual Menus

1. From the Menus & Toolbars section of the Toolbox, click


ContextMenuStrip and click the form

2. While the context menu strip is still selected, in the Properties window
click (Name) and type mnuWithProperties

3. Then click Items and click its ellipsis button

4. Under the Select Item And Add To List combo box, make sure MenuItem
is selected and click Add

5. On the right side, click Text and type Edit

C# 3.0 Practical Learning II 514


6. Click (Name) and type mnuEditProperty

7. On the left side, click Add and, on the right side, change the properties
as follows:
Text: Delete
(Name): mnuDeleteProperty

8. On the left side, click Add and, on the right side, change the properties
as follows:
Text: Clear
(Name): mnuClearProperties
 

9. Click OK

10. From the Menus & Toolbars section of the Toolbox, click
ContextMenuStrip and click the form

11. While the context menu strip is still selected, in the Properties window
click (Name) and type mnuNoProperty

12. On the form, under ContextMenuStrip, click Type Here

13. Type New Property and press Enter

14. On the form, under ContextMenuStrip, click New Property

15. In the Properties window, click (Name), type mnuNewProperty and press
Enter

C# 3.0 Practical Learning II 515


Using a Contextual Menu
By default, a newly created contextual menu is attached neither to the form
nor to any control on it. In order to display a context menu, you must assign
its name to the control. To support this, Control, the ancestor to all visual
controls of the .NET Framework, is equipped, and provides to its children, a
property named ContextMenuStrip, which is of type ContextMenuStrip.

To visually assign a contextual menu to a control during design, click the


control. In the Properties window, click the ContextMenuStrip field, then click
the arrow of its combo box, and select the menu. If you had created more
than one contextual menu, the combo box would show all of them and you
can choose the one you want to use as default.

To programmatically specify the contextual menu of a control, assign a


ContextMenuStrip object to its ContextMenuStrip property. Here is an
example:
void InitializeComponent()
{
System.Windows.Forms.ContextMenuStrip context =
new System.Windows.Forms.ContextMenuStrip();

ToolStripMenuItem mnuCut = new ToolStripMenuItem("Cut");


ToolStripMenuItem[] mnuEdit =
{
new ToolStripMenuItem("Copy"),
new ToolStripMenuItem("Paste")
};

context.Items.Add(mnuCut);
context.Items.AddRange(mnuEdit);

ContextMenuStrip = context;
}

After assigning a ContextMenuStrip object to a control, when you right-click


(actually when the user right-clicks) the control, the contextual menu would
display. The above code would produce:

C# 3.0 Practical Learning II 516


Practical Learning: Creating a Context Menu

1. Right-click the form and click View Code

2. Just above the Form1 constructor, declare a ListViewItem variable


named itmSelected
 
namespace AltairRealtors3
{
public partial class Form1 : Form
{
ListViewItem itmSelected;

public Form1()
{
InitializeComponent();
}

. . . No Change

3. Return to the form

4. Double-click an unoccupied area of the form to generate its Load event


and implement it as follows:
 
private void Form1_Load(object sender, EventArgs e)
{
itmSelected = new ListViewItem();
lvwProperties.ContextMenuStrip = mnuNoProperty;
}

C# 3.0 Practical Learning II 517


5. Return to the form and click the list view

6. In the Properties window, click the Events button and double-click


MouseDown

7. Implement the event as follows:


 
private void lvwProperties_MouseDown(object sender,
MouseEventArgs e)
{
if (e.Button == MouseButtons.Right)
{
if (lvwProperties.SelectedItems.Count > 0)
itmSelected =
lvwProperties.SelectedItems[0];
else
itmSelected = null;
}
}

8. Return to the form

Coding Contextual Menus


In your application, you can create as many contextual menus as you want. If
you have different controls, each can have its own contextual menu or many
can share a contextual menu. Also, you can use different contextual menus
for a control and decide what menu to display when/why.

There is nothing particularly specific with writing code for a popup menu item.
You approach it exactly as if you were dealing with a menu item of a main
menu. You can write code for an item of a popup menu independent of any
other item of a main menu. If you want an item of a popup menu to respond
to the same request as an item of a main menu, you can write code for one
of the menu items (either the item on the main menu or the item on the
popup menu) and simply call its Click event in the event of the other menu
item.

Practical Learning: Using Various Contextual Menus

1. On the form, click the list view if necessary.


In the events section of the Properties window, double-click
ItemSelectionChanged

2. Implement the event as follows:


 
private void lvwProperties_ItemSelectionChanged(object sender,
ListViewItemSelectionChangedEventArgs e)
{

C# 3.0 Practical Learning II 518


if (e.Item == itmSelected)
lvwProperties.ContextMenuStrip = mnuNoProperty;
else
lvwProperties.ContextMenuStrip =
mnuWithProperties;
}

3. Return to the form

4. Under the form, click mnuWithProperties

5. On the form, double-click Edit and implement its event as follows:


 
private void mnuEditProperty_Click(object sender, EventArgs e)
{
// Prepare to open the AvailableProperties dialog box
RealEstateProperty dlgProperty = new RealEstateProperty();

// Make sure an item, and only one, is selected


if ((lvwProperties.SelectedItems.Count == 0) ||
(lvwProperties.SelectedItems.Count > 1))
return;

// Identify the item that is currently selected


ListViewItem lviCurrent = lvwProperties.SelectedItems[0];

// Display the ItemDetails dialog box with the item number


dlgProperty.txtPropertyNumber.Text = lviCurrent.Text;
dlgProperty.cbxPropertyTypes.Text =
lviCurrent.SubItems[1].Text;
dlgProperty.txtAddress.Text = lviCurrent.SubItems[2].Text;
dlgProperty.txtCity.Text = lviCurrent.SubItems[3].Text;
dlgProperty.cbxStates.Text = lviCurrent.SubItems[4].Text;
dlgProperty.txtZIPCode.Text = lviCurrent.SubItems[5].Text;
dlgProperty.txtBedrooms.Text = lviCurrent.SubItems[6].Text;
dlgProperty.txtBathrooms.Text = lviCurrent.SubItems[7].Text;
dlgProperty.txtMarketValue.Text =
lviCurrent.SubItems[8].Text;

if (dlgProperty.ShowDialog() == DialogResult.OK)
{
lvwProperties.SelectedItems[0].Text =
dlgProperty.txtPropertyNumber.Text;
lvwProperties.SelectedItems[0].SubItems[1].Text =
dlgProperty.cbxPropertyTypes.Text;
lvwProperties.SelectedItems[0].SubItems[2].Text =
dlgProperty.txtAddress.Text;
lvwProperties.SelectedItems[0].SubItems[3].Text =
dlgProperty.txtCity.Text;
lvwProperties.SelectedItems[0].SubItems[4].Text =
dlgProperty.cbxStates.Text;
lvwProperties.SelectedItems[0].SubItems[5].Text =
dlgProperty.txtZIPCode.Text;
lvwProperties.SelectedItems[0].SubItems[6].Text =
dlgProperty.txtBedrooms.Text;

C# 3.0 Practical Learning II 519


lvwProperties.SelectedItems[0].SubItems[7].Text =
dlgProperty.txtBathrooms.Text;
lvwProperties.SelectedItems[0].SubItems[8].Text =
dlgProperty.txtMarketValue.Text;
}
}

6. Return to the form

7. On the form, double-click Delete and implement its event as follows:


 
private void mnuDeleteProperty_Click(object sender, EventArgs e)
{
if (lvwProperties.SelectedItems.Count == 0)
return;

DialogResult answer = MessageBox.Show("Are you sure you want


" +
"to delete that
property?",
"Delete Property",

MessageBoxButtons.YesNo,
MessageBoxIcon.Question);

if (answer == DialogResult.Yes)
lvwProperties.SelectedItems[0].Remove();
}

8. Return to the form

9. On the form, double-click Clear and implement its event as follows:


 
private void mnuClearProperties_Click(object sender, EventArgs
e)
{
DialogResult answer = MessageBox.Show("Are you sure you want
" +
"to delete all
properties?",
"Remove all
Properties",

MessageBoxButtons.YesNo,

MessageBoxIcon.Question);

if (answer == DialogResult.Yes)
lvwProperties.Items.Clear();
}

10. Return to the form

11. Under the form, click mnuNoProperty

C# 3.0 Practical Learning II 520


12. On the form, under ContextMenuStrip, double-click New Property and
implement its event as follows:
 
private void mnuNewProperty_Click(object sender, EventArgs e)
{
mnuFileNewProperty_Click(sender, e);
}

13. Execute the application and test it

14. Right-click an empty line of the list view to see the contextual menu and
click New Property
 

15. Right-click the list view and click Edit


 

C# 3.0 Practical Learning II 521


 

16. Right-click a row on the form and click Delete

17. Accept to delete the property

18. Close the form and return to your programming environment

The Font Dialog Box


 

Introduction to the Font Dialog Box

C# 3.0 Practical Learning II 522


 

Introduction
To assist the user with selecting a font for an application, Microsoft
Windows provides the Font dialog box:

The Font dialog box appears with three combo boxes of a simple style, a group box that
contains a label, a combo box of a drop down list style, and two buttons (labeled OK and
Cancel).

The list of fonts installed on the computer appear in the Font combo box. To select a
font, the user can start typing its name and the combo box would present suggested
names. The user can also scroll down in the list and click the desired font.

The four types of font styles are listed in the Font Style combo box: the
Regular, the Italic, the Bold, and the combined Bold Italic styles.

The possible sizes are listed in the Size combo box. The user can click a size
or scroll down in the list to find the desired size. The user is allowed to use a
size that is not listed. To use it, the user can click in the text box side of the
control, delete the number, and type the new number.

As the user is making the selections that would define a font, the Sample
label shows a preview of the selection.

C# 3.0 Practical Learning II 523


The Script combo box allows the user to specify an alphabetic category. The
options are Western (the default for a US-English computer), Greek, Turkish,
Central European, and Cyrillic.

After making the selections in the Font, the Font Style, and the Size combo
boxes, the user can click OK.

As an option, the Font dialog box can allow the user to apply two more styles
and a color to the selected font. To make this possible, the lower-left section
of the dialog box can be equipped with an Effects group box. Here is an
example:

The Effects group box is equipped with a Strikeout check box, an Underline
check box, and a Color combo box. To apply a style, the user can click its
check box. To remove a style, the user can uncheck it. To select a color, the
user can click the arrow of the Color combo box and select a color.

As mentioned already, after making the selections, the user can click OK. To
dismiss the selections, the user can click Cancel or press Esc. After clicking OK
or Cancel, the dialog box would be closed. As an alternative, the Font dialog
box can be equipped with an Apply button. In this case, when the dialog box
comes up, the user can make selections. If the user clicks Apply, the new
selections would be executed, as if the user had clicked OK, but the dialog
box would continue displaying. After clicking Apply, even if the user clicks
Cancel, the changes made on the dialog box would be validated.

Creating a Font Dialog Box

C# 3.0 Practical Learning II 524


In the .NET Framework, the Font dialog box is represented by the
FontDialog class. The FontDialog class is derived from the CommonDialog
class.

At design time, to provide a Font dialog to your application, from the Dialogs
section of the Toolbox, you can click the FontDialog button and click the
form. To programmatically provide a Font dialog box to your application,
declare a variable of type FontDialog and use the new operator to allocate its
memory.

To display a Font dialog box to the user, call its ShowDialog() method. Here
is an example:
using System;
using System.Drawing;
using System.Windows.Forms;

public class Exercise : System.Windows.Forms.Form


{
FontDialog dlgFont;

public Exercise()
{
InitializeComponent();
}

void InitializeComponent()
{
dlgFont= new FontDialog();

dlgFont.ShowDialog();
}
}

public class Program


{
static int Main()
{
System.Windows.Forms.Application.Run(new Exercise());
return 0;
}
}

This would produce:

C# 3.0 Practical Learning II 525


Characteristics of the Font Dialog Box

The Font of a Font Dialog Box


After creating a Font dialog box, you can display it to the user. The dialog box
is configured to select a default font, Regular as the default style, and 8 as
the default size. If you want, when the dialog box comes up, you can define
the font you want it to display. To support this, the FontDialog class is
equipped with a property named Font.

At design time, to define the font, click the FontDialog object under the form.
In the Properties window, click Font and click its ellipsis button. This would
display the Font dialog box. You can make your selections and then click OK.
At run time, to specify the font, first create a Font object, and then assign it
to the Font property of the FontDialog variable. Here is an example:
void InitializeComponent()
{
Font fnt = new Font("Garamond", 18.00F,
FontStyle.Italic);

dlgFont = new FontDialog();


dlgFont.Font = fnt;

dlgFont.ShowDialog();
}

This would produce:

C# 3.0 Practical Learning II 526


At any time, to make the dialog box display its default values, you can call its
Reset() method. The syntax of the Reset() method is:

public override void Reset ();

On the other hand, after the user has made the selections on the dialog box
and clicked OK (or Apply), to get the list of selections the user made, you can
get the values of its Font property.

The Apply Button


As you may know already, after making the selections on the dialog box, the
user can click OK. In this case, when you call the ShowDialog() method, you
can find out whether this method returns DialogResult.OK. If it does, you
can get all the returned values of the dialog box to know what changes the
user made.

Besides OK and Cancel, you can equip a font dialog box with a button labeled
Apply. To support this, the FontDialog class is equipped with a Boolean
property named ShowApply. By default, this property is set to false, which
means the button would be hidden. If you want to show the button, set this
property to true. Here is an example:
void InitializeComponent()
{
dlgFont = new FontDialog();

dlgFont.ShowColor = true;

dlgFont.ShowApply = true;

dlgFont.ShowDialog();

C# 3.0 Practical Learning II 527


}

This would produce:

As opposed to the OK button, when the user clicks Apply, the dialog box does
not close and therefore (its ShowDialog() method) does not return a
DialogResult result. Instead, the dialog box fires an Apply event. This
event is of type EventArgs, which means it does not give your information
about what the user did (or did not do). Fortunately, to get information about
the state or the values of the dialog, you can simply inquire about its various
properties and you would get all the information you need without any effort.

The Effects of a Font Dialog Box


We have already mentioned that the Font dialog box can display or not
display the Effects group box. This characteristic is controlled by the
ShowEffects Boolean property. When this property is set to true, the dialog
box would display an Effects group box that contains a Strikeout and an
Underline check boxes. If the ShowEffects property is set to false, the whole
section would be hidden.

The Color Combo Box


Besides the font definition, you may want the user to apply a color to the
font. To support this, the FontDialog class is equipped with the ShowColor
Boolean property. By default, this property is set to false. Because the Color
combo box is contained in the Effects group box, before being able to display
it, you must set the ShowEffects property to true. Then, to show the Color
combo box, you can set its property to true.

C# 3.0 Practical Learning II 528


If the Font dialog box is configured to show the Color combo box, by default,
when the dialog box displays, the Color combo box selects the black color. If
you want, you can make it display a different color. To do this, at design
time, access the Properties window for the FontDialog object, click the arrow
of the Color field and select a color. To programmatically specify a color,
assign the desired color to the Color property:
void InitializeComponent()
{
Font fnt = new Font("Garamond", 18.00F,
FontStyle.Italic);

dlgFont = new FontDialog();


dlgFont.Font = fnt;

dlgFont.ShowColor = true;
dlgFont.Color = Color.Red;

dlgFont.ShowDialog();
}

This would produce:

After using the dialog box, if the user had selected a color and clicked OK (or
Apply), to find out the color the user had selected, get the value of the Color
property.

C# 3.0 Practical Learning II 529


Windows Control: The List Box
 

Description
A list box presents a list of items to choose from. Each item displays on a line.
The user makes a selection by clicking in the list. Once clicked, the item or
line on which the mouse landed becomes highlighted, indicating that it is the
current choice. Here is an example:

After an item has been selected, to make a different selection, the user would
click another. The new clicked item becomes selected or highlighted; the
previously selected item looses its highlighting attribute. The user can also
change the selection by pressing the up or down arrow keys.

List boxes are categorized in two types: single and multi-selection. The
second category allows a user to select more than one item by pressing Ctrl
to select items at random or by pressing Shift to select items in a range.

One of the main reasons for using a list box is to display a list of items to the
user. Sometimes the list would be very large. If the list is longer than the
available client area of the control, the control would be equipped with a
scroll bar that allows the user to navigate up and down to access all items of
the list. You will have the option of deciding how many items to display on
the list.

Practical Learning: Introducing List Boxes

1. Start Microsoft Visual C# and create a new Windows Application


named MusicalInstrumentStore1

C# 3.0 Practical Learning II 530


2. In the Solution Explorer, right-click Form1.cs and click Rename

3. Type MusicStore.cs and press Enter

Creating a List Box


To support list boxes, the .NET Framework provides the ListBox class. At
design time, to add a list box to an application, from the Common Controls
section of the Toolbox, click the ListBox control and click the form or the
control that will host it. To programmatically create a list box, declare a
variable of type ListBox, use the new operator to allocate memory it, and add
it to the Controls property of its eventual parent.
using System;
using System.Drawing;
using System.Windows.Forms;

public class Exercise : System.Windows.Forms.Form


{
ListBox lbxFamily;

public Exercise()
{
InitializeComponent();
}

private void InitializeComponent()


{
lbxFamily = new ListBox();

Controls.Add(lbxFamily);
}
}

public class Program


{
static int Main()
{
System.Windows.Forms.Application.Run(new Exercise());
return 0;
}
}

In our applications, the names of the list-based controls will be in plural. This is
not a rule and it is not based on any preconceived standard.

Practical Learning: Creating List Boxes

C# 3.0 Practical Learning II 531


1. Design the form as follows:
 

Control Text Name Other Properties

Musical Instrument
GroupBox    
Selection

Label Categories    

Label Types    

Label Items    

C# 3.0 Practical Learning II 532


ListBox   lbxCategories  

ListBox   lbxTypes  

ListBox   lbxItems  

GroupBox Selected Items    

Label   Part #  

Label   Description  

Label   Unit Price  

Label   Qty  

Label   Sub Total  

TextBox   txtPartID1  

TextBox   txtDescription1  

TextBox 0.00 txtUnitPrice1 TextAlign: Right

TextBox 0 txtQantity1 TextAlign: Right

TextBox 0.00 txtSubTotal1 TextAlign: Right

Button Rmv btnRemove1  

C# 3.0 Practical Learning II 533


TextBox   txtPartID2  

TextBox   txtDescription2  

TextBox 0.00 txtUnitPrice2 TextAlign: Right

TextBox   txtQuantity2 TextAlign: Right

TextBox 0.00 txtSubTotal2 TextAlign: Right

Button Rmv btnRemove2  

TextBox   txtPartID3  

TextBox   txtDescription3  

TextBox 0.00 txtUnitPrice3 TextAlign: Right

TextBox 0 txtQuantity3 TextAlign: Right

TextBox 0.00 txtSubTotal3 TextAlign: Right

Button Rmv btnRemove3  

TextBox   txtPartID4  

TextBox   txtDescription4  

TextBox 0.00 txtUnitPrice4 TextAlign: Right

C# 3.0 Practical Learning II 534


TextBox   txtQuantity4 TextAlign: Right

TextBox 0.00 txtSubTotal4 TextAlign: Right

Button Rmv btnRemove4  

TextBox   txtPartID5  

TextBox   txtDescription5  

TextBox 0.00 txtUnitPrice5 TextAlign: Right

TextBox 0 txtQuantity5 TextAlign: Right

TextBox 0.00 txtSubTotal5 TextAlign: Right

Button Rmv btnRemove5  

TextBox   txtPartID6  

TextBox   txtDescription6  

TextBox 0.00 txtUnitPrice6 TextAlign: Right

TextBox 0 txtQuantity6 TextAlign: Right

TextBox 0.00 txtSubTotal6 TextAlign: Right

Button Rmv btnRemove6  

C# 3.0 Practical Learning II 535


Button Close btnClose  

Label   Order Total:  

TextBox 0.00 txtTotalOrder TextAlign: Right

2. Save the form

The Items of a List Box


 

Introduction
Like every control, when creating a list box, make sure you give it a name.
Once the list box is positioned on a container, as done with other controls,
you can move it by clicking and dragging the control. You can also resize it
using any of the techniques we learned to add, position, move, and resize
controls. If the list will cover many items, design it so its height can display 8
items at a time. Otherwise, for a list of 8 or less items, use only the necessary
height that would accommodate all of the items.

Adding Items to a List Box


The most important characteristic of a list box is the list of items it contains.
This list is represented by the Items property. The Items list is created and
managed by a ListBox-nested class named ObjectCollection.
ObjectCollection is a collection class that implements the IList, the
ICollection, and the IEnumerable interfaces.

At design time, to create a list of items, access the Properties window of the
list box and click the ellipsis button of the Items field. This would open the
String Collection Editor:

C# 3.0 Practical Learning II 536


In the empty window, you can type an item, press Enter, add another, and so
on. After creating the list, you can click OK. To programmatically add an item
to the list, access the Items property, call its Add() method, and pass the
new item. You can do this continually for each item. Here are examples:
private void InitializeComponent()
{
lbxFamily = new ListBox();
lbxFamily.Location = new Point(12, 12);
lbxFamily.Items.Add("Son");
lbxFamily.Items.Add("Daughter");
lbxFamily.Items.Add("Father");
lbxFamily.Items.Add("Mother");

Controls.Add(lbxFamily);
}

This would produce:

You can also first create an array of items and then add that array to the
collection. To support this, the ObjectCollection class provides the
AddRange() method. Here is an example:

private void InitializeComponent()


{
lbxFamily = new ListBox();
lbxFamily.Location = new Point(12, 12);
lbxFamily.Items.Add("Son");
lbxFamily.Items.Add("Daughter");
lbxFamily.Items.Add("Father");
lbxFamily.Items.Add("Mother");

C# 3.0 Practical Learning II 537


string[] strMembers = { "Niece", "Nephew", "Uncle" };
lbxFamily.Items.AddRange(strMembers);

Controls.Add(lbxFamily);
}

This would produce:

If you use either the Add() or the AddRange() method to add an item or a
group of items, the item or the group would be added to the end of the list, if
a list exists already. To insert a new item somewhere inside of the list, call
the Insert() method.

Practical Learning: Adding Items to a List Box

1. On the form, click the Categories list box

2. In the Properties window, click Items and click its ellipsis button

3. Type Guitars and press Enter

4. Type Bass and press Enter

5. Complete the list to have the following items:


 

Guitars
Bass
Keyboards
Drums & Percussion
Band & Orchestra
Recording & Sound
Folk Instruments
Books & Videos
Accessories

6. Click OK

7. To programmatically add items to the list boxes, on the form, double-


click an unoccupied area to access its Load event and implement it as

C# 3.0 Practical Learning II 538


follows:
 
private void MusicStore_Load(object sender, EventArgs e)
{
lbxTypes.Items.Add("Electric Guitars");
lbxTypes.Items.Add("Acoustic Guitars");
lbxTypes.Items.Add("Acoustic-Electric Guitars");
lbxTypes.Items.Add("Amplifiers");
lbxTypes.Items.Add("Effects");
lbxTypes.Items.Add("Microphones");
lbxTypes.Items.Add("Accessories");
lbxTypes.Items.Add("Value Packages");
}

8. Execute the application to test it

9. After using the form, close it and return your programming environment

10. On the main menu, click Project -> Add Class...

11. In the Templates list, make sure Class is select.


Set the name to PartDescription and click Add

12. Complete the class as follows:


 
using System;

namespace MusicalInstrumentStore1
{
class PartDescription
{
private string number;
private string discr;
private decimal uprice;

public string PartNumber


{
get { return number; }
set { number = value; }
}

public string PartName


{
get { return discr; }
set { discr = value; }
}

public decimal UnitPrice


{
get { return uprice; }
set { uprice = value; }
}

public PartDescription()

C# 3.0 Practical Learning II 539


{
this.number = "";
this.discr = "";
this.uprice = 0.00M;
}

public PartDescription(string nbr,


string name,
decimal price)
{
this.number = nbr;
this.discr = name;
this.uprice = price;
}

public override string ToString()


{
return this.PartNumber + " " +
this.PartName + " " +
this.UnitPrice.ToString();
}
}
}

13. Access the MusicStore.cs file and create a few arrays as follows:
 
namespace MusicalInstrumentStore1
{
public partial class MusicStore : Form
{
string[] CatBass = {
"Electric Bass", "Acoustic-Electric Bass",
"Amplifiers", "Effects", "Accessories" };

string[] CatKeyboard = {
"Pianos", "Organs", "Synthesizers",
"Portable", "Workstations", "Arrangers",
"Stands", "Amps", "Pedals", "Accessories" };

string[] CatDrums = {
"Acoustic Drums", "Cymbals",
"Electronic Percussion", "World Percussion" };

string[] CatBand = {
"Trumpets", "Trombones", "Saxophones",
"Clarinets", "Flutes", "Baritones", "Tubas",
"Oboes", "Recorders", "Accessories" };

string[] CatAccessories = {
"Headphones", "Strings", "Slides", "Metronomes",
"Tuners", "Music Stands", "Cases", "Cables",
"Hearing Protection", "Electric Guitar Bags",
"Guitar Pedals", "Cleaning/Care" };

PartDescription[] ElectricGuitars =

C# 3.0 Practical Learning II 540


{
new PartDescription("293027",
"Gibson Les Paul Vintage Solid
Guitar",
850.75M),
new PartDescription("972355",
"Fender Standard Stratocaster Electric
Guitar",
435.95M),
new PartDescription("390057",
"Gibson Les Paul Standard Left-Handed 50s Neck
Electric Guitar",
2400.00M),
new PartDescription("297548",
"Schecter C-1 Hellraiser Electric Guitar",
649.95M),
new PartDescription("284704",
"Gretsch Guitars G5120 Electromatic Hollowbody
Electric Guitar",
595.95M),
new PartDescription("293472",
"Rickenbacker 360 12-String Electric Guitar",
2195.95M),
new PartDescription("208476",
"Steinberger Synapse ST-2FPA TranScale Custom
Electric Guitar",
1045.50M),
new PartDescription("253463",
"Gibson EDS 1275 Double-Neck Electric Guitar",
3050.25M),
new PartDescription("225747",
"Fender American Stratocaster Left-Handed Electric
Guitar",
950.50M),
new PartDescription("274875",
"Epiphone Dot Studio Semi-Hollow Electric Guitar",
295.25M)
};

PartDescription[] AcousticGuitars =
{
new PartDescription("224885",
"Epiphone Hummingbird Acoustic Guitar",
245.55M),
new PartDescription("283407",
"Dean V Coustic Thin Body Acoustic-Electric Guitar",
205.50M),
new PartDescription("275111",
"Yamaha FG720S 12-String Acoustic Guitar",
325.55M),
new PartDescription("249036",
"Rogue RA-100D Dreadnought Acoustic Guitar",
82.95M),
new PartDescription("285507",
"Alvarez RD8 Regent Series Dreadnought Acoustic
Guitar",

C# 3.0 Practical Learning II 541


220.50M),
new PartDescription("283746",
"Epiphone EJ-200 Acoustic Guitar", 350.50M)
};

PartDescription[] ElectricBasses =
{
new PartDescription("248780",
"Epiphone Thunderbird IV Bass",
325.50M),
new PartDescription("203487",
"Squier® Vintage Modified '70s Jazz Bass",
305.95M),
new PartDescription("204633",
"Fender Standard Precision Bass",
450.75M),
new PartDescription("297548",
"Music Man StingRay 5-String Bass Guitar",
1485.95M)
};

PartDescription[] AcousElectBasses =
{
new PartDescription("248780",
"Ibanez AEB10E Acoustic-Electric Bass Guitar with
Onboard Tuner",
335.50M),
new PartDescription("203487",
"Dean Playmate EABC 5-String Cutaway Acoustic-
Electric Bass",
285.95M),
new PartDescription("204633",
"Fender BG-32 Acoustic/Electric Bass Guitar",
495.75M),
new PartDescription("634974",
"Gibson Thunderbird IV Bass", 1500.00M),
new PartDescription("674950",
"Rogue VB-100 Violin Bass", 255.95M),
new PartDescription("634742",
"Squier Standard P Bass 4-String Bass",
220.75M),
new PartDescription("637904",
"Peavey Millennium BXP 4-String Bass",
210.95M)
};

PartDescription[] Pianos =
{
new PartDescription("584603",
"Williams ETUDE Console Piano",
450.95M),
new PartDescription("504724",
"Rolan EP-760C Digital Piano w/Stand",
650.95M)
};

C# 3.0 Practical Learning II 542


PartDescription[] Synthetizers =
{
new PartDescription("582970",
"Alesis ION 49-Key 1K DSP Synthesizer",
750.50M),
new PartDescription("524885",
"Korg MicroKORG Synthesizer/Vocoder",
350.75M),
new PartDescription("549085",
"Yamaha YDP223 Digital Piano",
1450.00M),
new PartDescription("529307",
"Access Virus kc 5-Octave Synth",
1915.55M)
};

PartDescription[] Books =
{
new PartDescription("883670",
"Alfred Guitar for the Absolute Beginner",
16.55M),
new PartDescription("837654",
"Hal Leonard Guitar Tab White Pages",
20.95M),
new PartDescription("843047",
"Carl Fischer Guitar Grimoire Progressions and
Improvisation",
24.75M),
new PartDescription("845716",
"Bill Edwards Publishing Fretboard logic Spc Ed.",
17.95M),
new PartDescription("833427",
"Walrus Productions Guitar Chord Poster",
6.85M)
};

PartDescription[] Cables =
{
new PartDescription("188370",
"Musician's Friend Professional Cable",
4.55M),
new PartDescription("183614",
"Monster Cable S-100 Straight Cable",
20.95M),
new PartDescription("143047",
"Hosa TRS-TRS Stereo 1/4\" Cable",
4.65M),
new PartDescription("145716",
"Mogami Silver Series Cable",
12.95M)
};

. . . No Change

C# 3.0 Practical Learning II 543


14. Save all

Selecting an Item in a List Box


To an item from a list box, the user must locate and click the desired item.
That item is said to have been selected. To programmatically select an item,
you can assign the index of the desired item to the ListBox.SelectedIndex
property. The indices of the items of a list box are stored in a zero-based
array. This means that the first item has an index of 0, the second has an
index of 1, and so on. Here is an example that will select the fourth item of 
the list:
private void InitializeComponent()
{
lbxFamily = new ListBox();
lbxFamily.Location = new Point(12, 12);
lbxFamily.Items.Add("Son");
lbxFamily.Items.Add("Daughter");
lbxFamily.Items.Add("Father");
lbxFamily.Items.Add("Mother");

string[] strMembers = { "Niece", "Nephew", "Uncle" };


lbxFamily.Items.AddRange(strMembers);

Controls.Add(lbxFamily);

lbxFamily.SelectedIndex = 3;
}

This would produce:

After an item has been selected, to find out the index of the item that is
currently selected, get the value of the ListBox.SelectedIndex property.

To select an item, the user can click it in the list box. When an item has been
clicked, the list box fires a SelectedIndexChanged event. Because selecting
an item is the most regularly performed operation on a list box,
SelectedIndexChanged is the default event of a list box. This event is of
type EventArgs which means that it does not provide any significant
information other than to let you know that an item has been selected.
Nonetheless, this event allows you to easily check if an item has been
selected and what item has been selected.

C# 3.0 Practical Learning II 544


To fire a SelectedIndexChanged event and to test what item has been
selected in the list, you can double-click the list box.

The ListBox.SelectedIndex property allows you either to select an item or


to find out what item is selected, using its index, that is, the numeric position
of the item in the list. If you know the identity, such as the name, of the item
you want to select, or if you want to identify the selected item based on its
name, you can use the ListBox.SelectedItem property instead. This
member identifies the item instead of locating it.

By default, the user can select only one item in the list. If you want the user
to be able to select more than one item, change the value of the
SelectionMode property. This property is based on the SelectionMode
enumeration. After the user has selected more than one item, to get the
indexes of the items that are selected, you can access the
ListBox.SelectedIndices property which holds that list.

Practical Learning: Selecting an Item From a List Box

1. Display the form and double-click the Categories list box

2. Implement its event as follows:


 
private void lbxCategories_SelectedIndexChanged(object sender,
EventArgs e)
{
if (lbxCategories.SelectedItem == (object)"Guitars")
{
lbxTypes.Items.Add("Electric Guitars");
lbxTypes.Items.Add("Acoustic Guitars");
lbxTypes.Items.Add("Acoustic-Electric Guitars");
lbxTypes.Items.Add("Amplifiers");
lbxTypes.Items.Add("Effects");
lbxTypes.Items.Add("Microphones");
lbxTypes.Items.Add("Accessories");
lbxTypes.Items.Add("Value Packages");
}
else if (lbxCategories.SelectedItem == (object)"Bass")
lbxTypes.Items.AddRange(CatBass);
else if (lbxCategories.SelectedItem ==
(object)"Keyboards")
lbxTypes.Items.AddRange(CatKeyboard);
else if (lbxCategories.SelectedItem == (object)"Drums &
Percussion")
lbxTypes.Items.AddRange(CatDrums);
else if (lbxCategories.SelectedItem == (object)"Band &
Orchestra")
lbxTypes.Items.AddRange(CatBand);
else if (lbxCategories.SelectedItem == (object)"Books &
Videos")
{

C# 3.0 Practical Learning II 545


lbxTypes.Items.Add("Books");
lbxTypes.Items.Add("DVDs");
}
else if (lbxCategories.SelectedItem ==
(object)"Accessories")
lbxTypes.Items.AddRange(CatAccessories);
}

3. Return to the form

4. On the form, double-click the Types list box and implement its event as
follows:
 
private void lbxTypes_SelectedIndexChanged(object sender,
EventArgs e)
{
if( lbxTypes.SelectedItem == (object)"Electric
Guitars" )
foreach(PartDescription part in ElectricGuitars)
lbxItems.Items.Add(part);
else if (lbxTypes.SelectedItem == (object)"Acoustic
Guitars")
foreach(PartDescription part in
AcousticGuitars )
lbxItems.Items.Add(part);
else if (lbxTypes.SelectedItem == (object)"Electric
Bass")
foreach (PartDescription part in ElectricBasses)
lbxItems.Items.Add(part);
else if (lbxTypes.SelectedItem == (object)"Acoustic-
Electric Bass")
foreach (PartDescription part in
AcousElectBasses)
lbxItems.Items.Add(part);
else if (lbxTypes.SelectedItem == (object)"Pianos")
foreach(PartDescription part in Pianos)
lbxItems.Items.Add(part);
else if (lbxTypes.SelectedItem ==
(object)"Synthesizers")
foreach(PartDescription part in Synthetizers)
lbxItems.Items.Add(part);
else if (lbxTypes.SelectedItem == (object)"Books")
foreach(PartDescription part in Books)
lbxItems.Items.Add(part);
else if (lbxTypes.SelectedItem == (object)"Cables")
foreach(PartDescription part in Cables)
lbxItems.Items.Add(part);
}

C# 3.0 Practical Learning II 546


5. Execute the application to test it
 

6. After using the form, close it and return to your programming


environment

7. On the form, click the Items list box. In the Properties window, click the
Events button and double-click the DoubleClick field

8. Implement the event as follows:


 
internal void CalculateTotalOrder()
{
decimal subTotal1 = 0.00M, subTotal2 = 0.00M, subTotal3
= 0.00M,
subTotal4 = 0.00M, subTotal5 = 0.00M,
subTotal6 = 0.00M;
decimal orderTotal;

// Retrieve the value of each sub total


try
{
subTotal1 =
decimal.Parse(this.txtSubTotal1.Text);

C# 3.0 Practical Learning II 547


}
catch (FormatException)
{
MessageBox.Show("Invalid Value");
}

try
{
subTotal2 =
decimal.Parse(this.txtSubTotal2.Text);
}
catch (FormatException)
{
MessageBox.Show("Invalid Value");
}

try
{
subTotal3 =
decimal.Parse(this.txtSubTotal3.Text);
}
catch (FormatException)
{
MessageBox.Show("Invalid Value");
}
try
{
subTotal4 =
decimal.Parse(this.txtSubTotal4.Text);
}
catch (FormatException)
{
MessageBox.Show("Invalid Value");
}

try
{
subTotal5 =
decimal.Parse(this.txtSubTotal5.Text);
}
catch (FormatException)
{
MessageBox.Show("Invalid Value");
}

try
{
subTotal6 =
decimal.Parse(this.txtSubTotal6.Text);
}
catch (FormatException)
{
MessageBox.Show("Invalid Value");
}

// Calculate the total value of the sub totals

C# 3.0 Practical Learning II 548


orderTotal = subTotal1 + subTotal2 + subTotal3 +
subTotal4 + subTotal5 + subTotal6;

// Display the total order in the appropriate text box


this.txtTotalOrder.Text = orderTotal.ToString();
}

private void lbxItems_DoubleClick(object sender, EventArgs e)


{
// We will use a PartDescription object to identify the
selected item
PartDescription part = new PartDescription();

// When the user double-clicks an item, retrieve it


as
// a PartDescription object
part = (PartDescription)(lbxItems.SelectedItem);

// If the first Part # box is empty, then use it


if (txtPartID1.Text.Equals(""))
{
// Display the item number in the Part # text
box
txtPartID1.Text = part.PartNumber;
// Display the name of the selected item in
// the current Description text box
txtDescription1.Text = part.PartName;
// Display the unit price of this item in
// the corresponding Unit Price text box
this.txtUnitPrice1.Text =
part.UnitPrice.ToString();

// Enable the Remove button of the current item


btnRemove1.Enabled = true;

// Since an item was selected, set its quantity


to 1
this.txtQuantity1.Text = "1";
// Calculate the sub total of the current item
item
this.txtSubTotal1.Text = (part.UnitPrice *
1).ToString();
// Give focus to the Qty text box of the current
item
this.txtQuantity1.Focus();
}// If the previous Part # text box is not empty,
then use the next one
else if (this.txtPartID2.Text.Equals(""))
{
this.txtPartID2.Text = part.PartNumber;
this.txtDescription2.Text = part.PartName;
this.txtUnitPrice2.Text =
part.UnitPrice.ToString();

// Enable the Remove button of the current item


btnRemove2.Enabled = true;

C# 3.0 Practical Learning II 549


this.txtQuantity2.Text = "1";
this.txtSubTotal2.Text = (part.UnitPrice *
1).ToString();
this.txtQuantity2.Focus();
}
else if (this.txtPartID3.Text.Equals(""))
{
this.txtPartID3.Text = part.PartNumber;
this.txtDescription3.Text = part.PartName;
this.txtUnitPrice3.Text =
part.UnitPrice.ToString();

// Enable the Remove button of the current item


btnRemove3.Enabled = true;

this.txtQuantity3.Text = "1";
this.txtSubTotal3.Text = (part.UnitPrice *
1).ToString();
this.txtQuantity3.Focus();
}
else if (this.txtPartID4.Text.Equals(""))
{
this.txtPartID4.Text = part.PartNumber;
this.txtDescription4.Text = part.PartName;
this.txtUnitPrice4.Text =
part.UnitPrice.ToString();

// Enable the Remove button of the current item


btnRemove4.Enabled = true;

this.txtQuantity4.Text = "1";
this.txtSubTotal4.Text = (part.UnitPrice *
1).ToString();
this.txtQuantity4.Focus();
}
else if (this.txtPartID5.Text.Equals(""))
{
this.txtPartID5.Text = part.PartNumber;
this.txtDescription5.Text = part.PartName;
this.txtUnitPrice5.Text =
part.UnitPrice.ToString();

// Enable the Remove button of the current item


btnRemove5.Enabled = true;

this.txtQuantity5.Text = "1";
this.txtSubTotal5.Text = (part.UnitPrice *
1).ToString();
this.txtQuantity5.Focus();
}
else if (this.txtPartID6.Text.Equals(""))
{
this.txtPartID6.Text = part.PartNumber;
this.txtDescription6.Text = part.PartName;

C# 3.0 Practical Learning II 550


this.txtUnitPrice6.Text =
part.UnitPrice.ToString();

// Enable the Remove button of the current item


btnRemove6.Enabled = true;

this.txtQuantity6.Text = "1";
this.txtSubTotal6.Text = (part.UnitPrice *
1).ToString();
this.txtQuantity6.Focus();
} // If all Part # text boxes are filled, don't do
anything
else
return;

// Calculate the current total order and update the


order
CalculateTotalOrder();
}

9. Display the form and click the first text box under Unit Price

10. Press and hold Shift

11. Click each of the text boxes under Unit Price and each of the text boxes
under Qty

12. Release Shit

13. In the Properties window and in the Events section, double-click the
Leave field

14. Implement the event as follows:


 
private void txtUnitPrice1_Leave(object sender, EventArgs e)
{
int qty1 = 0, qty2 = 0, qty3 = 0,
qty4 = 0, qty5 = 0, qty6 = 0;
decimal unitPrice1 = 0.00M, unitPrice2 = 0.00M,
unitPrice3 = 0.00M,
unitPrice4 = 0.00M, unitPrice5 = 0.00M,
unitPrice6 = 0.00M;
decimal subTotal1, subTotal2, subTotal3,
subTotal4, subTotal5, subTotal6;

// Get the quantity of the current item


try
{
qty1 = int.Parse(txtQuantity1.Text);
}
catch (FormatException)
{
MessageBox.Show("Invalid Value");
}

C# 3.0 Practical Learning II 551


// Get the unit price of the current item
try
{
unitPrice1 = decimal.Parse(txtUnitPrice1.Text);
}
catch (FormatException)
{
MessageBox.Show("Invalid Value");
}

try
{
qty2 = int.Parse(txtQuantity2.Text);
}
catch (FormatException)
{
MessageBox.Show("Invalid Value");
}

try
{
unitPrice2 = decimal.Parse(txtUnitPrice2.Text);
}
catch (FormatException)
{
MessageBox.Show("Invalid Value");
}

try
{
qty3 = int.Parse(txtQuantity3.Text);
}
catch (FormatException)
{
MessageBox.Show("Invalid Value");
}

try
{
unitPrice3 = decimal.Parse(txtUnitPrice3.Text);
}
catch (FormatException)
{
MessageBox.Show("Invalid Value");
}

try
{
qty4 = int.Parse(txtQuantity4.Text);
}
catch (FormatException)
{
MessageBox.Show("Invalid Value");
}

try

C# 3.0 Practical Learning II 552


{
unitPrice4 = decimal.Parse(txtUnitPrice4.Text);
}
catch (FormatException)
{
MessageBox.Show("Invalid Value");
}

try
{
qty5 = int.Parse(txtQuantity5.Text);
}
catch (FormatException)
{
MessageBox.Show("Invalid Value");
}

try
{
unitPrice5 = decimal.Parse(txtUnitPrice5.Text);
}
catch (FormatException)
{
MessageBox.Show("Invalid Value");
}

try
{
qty6 = int.Parse(txtQuantity6.Text);
}
catch (FormatException)
{
MessageBox.Show("Invalid Value");
}

try
{
unitPrice6 = decimal.Parse(txtUnitPrice6.Text);
}
catch (FormatException)
{
MessageBox.Show("Invalid Value");
}

// Calculate the sub totals


subTotal1 = qty1 * unitPrice1;
subTotal2 = qty2 * unitPrice2;
subTotal3 = qty3 * unitPrice3;
subTotal4 = qty4 * unitPrice4;
subTotal5 = qty5 * unitPrice5;
subTotal6 = qty6 * unitPrice6;

// Display the sub totals in the corresponding text


boxes
txtSubTotal1.Text = subTotal1.ToString();
txtSubTotal2.Text = subTotal2.ToString();

C# 3.0 Practical Learning II 553


txtSubTotal3.Text = subTotal3.ToString();
txtSubTotal4.Text = subTotal4.ToString();
txtSubTotal5.Text = subTotal5.ToString();
txtSubTotal6.Text = subTotal6.ToString();

// Update the order


CalculateTotalOrder();
}

15. Return to the form

16. Double-click the first Rmv button and implement its Click event as
follows:
 
private void btnRemove1_Click(object sender, EventArgs e)
{
txtPartID1.Text = "";
txtDescription1.Text = "";
txtUnitPrice1.Text = "0.00";
txtQuantity1.Text = "0";
txtSubTotal1.Text = "0.00";
btnRemove1.Enabled = false;
}

17. Return to the form

18. Double-click the second Rmv button and implement its Click event as
follows:
 
private void btnRemove2_Click(object sender, EventArgs e)
{
txtPartID2.Text = "";
txtDescription2.Text = "";
txtUnitPrice2.Text = "0.00";
txtQuantity2.Text = "0";
txtSubTotal2.Text = "0.00";
btnRemove2.Enabled = false;
}

19. Return to the form

20. Double-click the third Rmv button and implement its Click event as
follows:
 
private void btnRemove3_Click(object sender, EventArgs e)
{
txtPartID3.Text = "";
txtDescription3.Text = "";
txtUnitPrice3.Text = "0.00";
txtQuantity3.Text = "0";
txtSubTotal3.Text = "0.00";
btnRemove3.Enabled = false;
}

C# 3.0 Practical Learning II 554


21. Return to the form

22. Double-click the fourth Rmv button and implement its Click event as
follows:
 
private void btnRemove4_Click(object sender, EventArgs e)
{
txtPartID4.Text = "";
txtDescription4.Text = "";
txtUnitPrice4.Text = "0.00";
txtQuantity4.Text = "0";
txtSubTotal4.Text = "0.00";
btnRemove4.Enabled = false;
}

23. Return to the form

24. Double-click the fifth Rmv button and implement its Click event as
follows:
 
private void btnRemove5_Click(object sender, EventArgs e)
{
txtPartID5.Text = "";
txtDescription5.Text = "";
txtUnitPrice5.Text = "0.00";
txtQuantity5.Text = "0";
txtSubTotal5.Text = "0.00";
btnRemove5.Enabled = false;
}

25. Return to the form

26. Double-click the sixth Rmv button and implement its Click event as
follows:
 
private void btnRemove6_Click(object sender, EventArgs e)
{
txtPartID6.Text = "";
txtDescription6.Text = "";
txtUnitPrice6.Text = "0.00";
txtQuantity6.Text = "0";
txtSubTotal6.Text = "0.00";
btnRemove6.Enabled = false;
}

27. Return to the form and double-click the Close button

28. Implement its Click event as follows:


 
private void btnClose_Click(object sender, System.EventArgs e)
{

C# 3.0 Practical Learning II 555


Close();
}

29. Execute the application to test it

Removing Items From a List Box


If you have an undesired item in a list box, you can remove it. To To support
this operation, the ObjectCollection class provides the Remove() method.
When calling it, pass the name of the item as argument. This means that you
must know the item you are trying to delete. If you call this method, the
compiler would look for the item in the list. If the item is found, it would be
deleted.

Instead of removing an item by its name or identification, you can use its
position. To do that, you can call the RemoveAt() method and pass the zero-
based index of the undesired item. If the index is valid, the item would be
deleted from the list.

To remove all items from the list, you can call the Clear() method.

Practical Learning: Removing Items From a List Box

1. Change the SelectedIndex events of the Types and the Items list boxes
as follows:
 
private void lbxCategories_SelectedIndexChanged(object sender,
EventArgs e)
{
lbxTypes.Items.Clear();
lbxItems.Items.Clear();

if (lbxCategories.SelectedItem == (object)"Guitars")
{
lbxTypes.Items.Add("Electric Guitars");
lbxTypes.Items.Add("Acoustic Guitars");
lbxTypes.Items.Add("Acoustic-Electric Guitars");
lbxTypes.Items.Add("Amplifiers");
lbxTypes.Items.Add("Effects");
lbxTypes.Items.Add("Microphones");
lbxTypes.Items.Add("Accessories");
lbxTypes.Items.Add("Value Packages");
}
else if (lbxCategories.SelectedItem == (object)"Bass")
lbxTypes.Items.AddRange(CatBass);
else if (lbxCategories.SelectedItem ==
(object)"Keyboards")
lbxTypes.Items.AddRange(CatKeyboard);
else if (lbxCategories.SelectedItem == (object)"Drums &
Percussion")
lbxTypes.Items.AddRange(CatDrums);

C# 3.0 Practical Learning II 556


else if (lbxCategories.SelectedItem == (object)"Band &
Orchestra")
lbxTypes.Items.AddRange(CatBand);
else if (lbxCategories.SelectedItem == (object)"Books &
Videos")
{
lbxTypes.Items.Add("Books");
lbxTypes.Items.Add("DVDs");
}
else if (lbxCategories.SelectedItem ==
(object)"Accessories")
lbxTypes.Items.AddRange(CatAccessories);
}

private void lbxTypes_SelectedIndexChanged(object sender,


EventArgs e)
{
lbxItems.Items.Clear();

if( lbxTypes.SelectedItem == (object)"Electric


Guitars" )
foreach(PartDescription part in ElectricGuitars)
lbxItems.Items.Add(part);
else if (lbxTypes.SelectedItem == (object)"Acoustic
Guitars")
foreach(PartDescription part in
AcousticGuitars )
lbxItems.Items.Add(part);
else if (lbxTypes.SelectedItem == (object)"Electric
Bass")
foreach (PartDescription part in ElectricBasses)
lbxItems.Items.Add(part);
else if (lbxTypes.SelectedItem == (object)"Acoustic-
Electric Bass")
foreach (PartDescription part in
AcousElectBasses)
lbxItems.Items.Add(part);
else if (lbxTypes.SelectedItem == (object)"Pianos")
foreach(PartDescription part in Pianos)
lbxItems.Items.Add(part);
else if (lbxTypes.SelectedItem ==
(object)"Synthesizers")
foreach(PartDescription part in Synthetizers)
lbxItems.Items.Add(part);
else if (lbxTypes.SelectedItem == (object)"Books")
foreach(PartDescription part in Books)
lbxItems.Items.Add(part);
else if (lbxTypes.SelectedItem == (object)"Cables")
foreach(PartDescription part in Cables)
lbxItems.Items.Add(part);
}

C# 3.0 Practical Learning II 557


2. Execute the application to test it. Here is an example:
 

3. Close the form and return to your programming environment

Sorting a List Box


After creating the list, by default, each item assumes the position it received
when it was added. If you want, you can rearrange them in ascending order.
To do this, set the ListBox.Sorted Boolean property to True. If you create
an unsorted list, then at one time get it sorted (for example, you can give the
user the ability to sort the list, by clicking a button), the list would be sorted.
If an item is added to the sorted list, the compiler would automatically insert
it to the right position following the alphabetical, ascending or chronological
order. If at another time you allow the user to “unsort” the list, the list would
keep its current order. If another item is added when the list is not sorted,
the item would be positioned at the end of the list. If you want the list to
have its original state, you would have to reset it through code.

Practical Learning: Sorting a List Box

1. On the form, click the Items list box

C# 3.0 Practical Learning II 558


2. In the Properties window, double-click Sorted to set its value to True

Characteristics of a List Box


 

The Scroll Bars


If you provide a longer list than the list box' height can display, it would have
a vertical scroll bar. Here is an example:
using System;
using System.Drawing;
using System.Windows.Forms;

public class Exercise : System.Windows.Forms.Form

{
ListBox lbxFamily;

public Exercise()
{
InitializeComponent();
}

private void InitializeComponent()


{
lbxFamily = new ListBox();
lbxFamily.Location = new Point(12, 12);
lbxFamily.Items.Add("Son");
lbxFamily.Items.Add("Daughter");
lbxFamily.Items.Add("Father");
lbxFamily.Items.Add("Mother");

string[] strMembers =
{
"Niece", "Nephew", "Uncle", "Aunt",
"Grand Father", "Grand Mother"
};
lbxFamily.Items.AddRange(strMembers);

Controls.Add(lbxFamily);

C# 3.0 Practical Learning II 559


}
}

public class Program


{
static int Main()
{

System.Windows.Forms.Application.Run(new Exercise());

return 0;
}
}

This would produce:

At design time, if just one or a few items are hidden by the scroll bar, you can
heighten it if the form provides more space.

Consider the following example:


public class Exercise : System.Windows.Forms.Form
{
ListBox lbxBook;
Label lblTitle;

public Exercise()
{
InitializeComponent();
}

private void InitializeComponent()


{
lblTitle = new Label();
lblTitle.Text = "Book Titles";
lblTitle.Location = new Point(12, 12);

lbxBook = new ListBox();


lbxBook.Location = new Point(12, 36);

lbxBook.Items.Add("College Algebra");;

lbxBook.Items.Add("Finite Mathematics");
lbxBook.Items.Add("Mathematical Structures");

lbxBook.Items.Add("MCAD 70-316 Training Guide");

C# 3.0 Practical Learning II 560


lbxBook.Items.Add("C++ Builder 6 Developer's Guide");

Controls.Add(lblTitle);
Controls.Add(lbxBook);
}
}

This would produce:

If at least one of the items of the list box is wider than the width of the
control, the right side(s) of that (those) may disappear. To allow the user to
see the hidden part of the item(s), you should display a horizontal scroll bar.
To support this, the ListBox class is equipped with a Boolean property
named HorizontalScrollbar. To make a list box display a horizontal scroll
bar, at design time, access the Properties window for the list box and set its
HorizontalScrollbar property to True. You can also do this programmatically.
Here is an example:
private void InitializeComponent()
{
lblTitle = new Label();
lblTitle.Text = "Book Titles";
lblTitle.Location = new Point(12, 12);

lbxBook = new ListBox();


lbxBook.Location = new Point(12, 36);
lbxBook.Items.Add("College Algebra");;
lbxBook.Items.Add("Finite Mathematics");
lbxBook.Items.Add("Mathematical Structures");
lbxBook.Items.Add("MCAD 70-316 Training Guide");
lbxBook.Items.Add("C++ Builder 6 Developer's Guide");

bxBook.HorizontalScrollbar = true;

Controls.Add(lblTitle);
Controls.Add(lbxBook);
}

This property allows the operating system to find the widest item in the list
and provide a horizontal scroll bar that is long enough to display each item
when the user scrolls to the right. The above code would produce:

C# 3.0 Practical Learning II 561


If the list of items requires it, the list box would display both the vertical and
the horizontal scroll bars. Here is an example:
public class Exercise : System.Windows.Forms.Form
{
ListBox lbxBook;
Label lblTitle;

public Exercise()
{
InitializeComponent();
}

private void InitializeComponent()


{
lblTitle = new Label();
lblTitle.Text = "Book Titles";
lblTitle.Location = new Point(12, 12);

lbxBook = new ListBox();


lbxBook.Location = new Point(12, 36);
lbxBook.Items.Add("College Algebra");;
lbxBook.Items.Add("Finite Mathematics");
lbxBook.Items.Add("Mathematical Structures");
lbxBook.Items.Add("MCAD 70-316 Training Guide");
lbxBook.Items.Add("C++ Builder 6 Developer's Guide");
lbxBook.Items.Add("La Bible de Jérusalem");
lbxBook.Items.Add("Patterns for a Purpose");
lbxBook.HorizontalScrollbar = true;

Controls.Add(lblTitle);
Controls.Add(lbxBook);
}
}

This would produce:

C# 3.0 Practical Learning II 562


If you prefer to decide how much width should be allowed, then set the
desired value in the HorizontalExtent property.

Practical Learning: Implementing List Boxes

1. Display the form and click the most right list box. Using the Properties
window, set its HorizontalScrollbar property to True

2. Execute the application and process an order

3. After using it, close the form and return to your programming
environment

A Multi-Column List Box


When you create a list of items, they appear in one column. If the number of
items exceeds the height, a scrollbar would appear on the control. An
alternative you can use is to span the list to more than one column. To
support this, the ListBox class is equipped with the MultiColumn Boolean
property. At design time, you can set this characteristic in the Properties
window. By default, the MultiColumn value is set to False, which means the
items appear in one column. If you set this property to True, then the
compiler would decide if or when the control needs the columns, based on
the number of items in the list. You can then specify the width of each
column using the ColumnWidth property.

A Custom Owner-Draw List Box


A list box is painted based on three types or style. This characteristic is
controlled by the DrawMode property. When its value is set to Normal, the
operating system would regularly draw each item of the list. If you want each
item of the list to display a graphic or a color, you must set the style to an
owner drawn type. The OwnerDrawFixed value allows you to set a desired
but same height for each item of the list. This height is controlled through the
ItemHeight property. You can set a different height for each item if you set
the list style to OwnerDrawVariable.

C# 3.0 Practical Learning II 563


Windows Control: The Numeric Up-
Down
 

Description
A spin button, also called a spin box, also called an up/down control, is a
Windows control equipped with two opposite arrow buttons .
The user clicks one of the arrow buttons at one time to increase or decrease
the current value of the control. The value held by the control is also called its
position. 

The values of an up/down control range from a minimum to a maximum.


When the up arrow button is clicked, the value of the control increases. If the
user clicks and holds the mouse on the up pointing arrow button, the value of
the control keeps increasing until it reaches its maximum and then stops. The
opposite behavior applies when the user clicks or holds the mouse on the
down-pointing arrow button.

Creating an Up-Down Control


The .NET Framework provides two types of spin buttons. The immediate
parent of the up/down control is the UpDownBase class.  This class provides
the characteristics and behaviors common to both types of up/down controls.

As it name implies, the numeric up-down control is made to display numeric


values. To use it, from the Common Controls section of the Toolbox, you can
click the NumericUpDown button and click the form or the container that
will host it. This control is based on the NumericUpDown class that you can
use to dynamically create the control. Here is an example:
using System;
using System.Drawing;
using System.Windows.Forms;

public class Exercise : System.Windows.Forms.Form


{
NumericUpDown nudCounter;

public Exercise()
{
InitializeComponent();

C# 3.0 Practical Learning II 564


}

private void InitializeComponent()


{
nudCounter = new NumericUpDown();
nudCounter.Location = new Point(12, 12);

Controls.Add(nudCounter);
}
}

public class Program


{
static int Main()
{

System.Windows.Forms.Application.Run(new Exercise());

return 0;
}
}

This would produce:

Characteristics of the Numeric Up-


Down Control
 

The Up-Down Alignment


In traditional Win32 programming, the spin button does not have a means of
displaying its value. This means that you usually have to accompany it with
another control such as a text box. You also have to decide whether to place
the text box to the left or the right side of the spin button control. Although
the .NET Framework's up-down controls don't have this limitation, you still

C# 3.0 Practical Learning II 565


have to decide whether to position the arrow buttons on the left or the right
side of the text box part. This property is controlled by the UpDownAlign
Boolean property whose default value is Right, which places the arrow
buttons on the right side.

If you want the buttons to be positioned on the left, set this property to Left.
The values of this property are managed through the LeftRightAlignment
enumeration of the UpDownBase parent class. Here is an example of aligning
the buttons to the left:
private void InitializeComponent()
{
nudCounter = new NumericUpDown();
nudCounter.Location = new Point(12, 12);
nudCounter.UpDownAlign = LeftRightAlignment.Left;

Controls.Add(nudCounter);
}

This would produce:

Intercepting the Arrow Keys


When a spin button control comes up, to use it, the user can click one of the
up or down-pointing buttons, which causes the value to change. The user can
also press the up or down arrow keys to change the value. The ability to use
the keyboard is controlled by the InterceptArrowKeys Boolean property,
whose default value is True, which means the user is allowed to use the
keyboard to change the value of the control. If for some (strange) reason you
want to prevent the user from changing the value using the keyboard, set this
property to False. If this property is set to True, remember that the user can
use the keyboard only after giving focus to the control, which is usually done
by pressing Tab a few times until the control receives focus. Another way the
user can change the value of the control is to manually edit the value of the
text box part of the control.

When the value of an spin button has been changed, the control fires a
ValueChanged() event. This event simply uses an EventArgs class as
argument. If the user decides to manually edit the value of the control by
typing a number in the text box part of the control, the spin button fires a
TextChanged() event.

The Minimum and the Maximum Values

C# 3.0 Practical Learning II 566


After adding the up-down control to a container such as a form, you change
its characteristics using the Properties window. Probably the most important
piece of information you would need from a spin button is the value it is
holding at a particular time. As mentioned already, the spin button navigates
from a minimum to a maximum value. The values of the control can be
natural or decimal numbers. They are actually defined as System.Decimal
types. These numbers range from a minimum controlled by the Minimum
property to a maximum value controlled by the Maximum property. By default,
a freshly added numeric up-down control on a form has its Minimum value set
to 0 and its Maximum value set to 100. You can change the values at design
time in the Properties window or programmatically as follows:
private void InitializeComponent()
{
nudCounter = new NumericUpDown();
nudCounter.Location = new Point(12, 12);
nudCounter.Minimum = 42.48M;
nudCounter.Maximum = 3822046.06M;

Controls.Add(nudCounter);
}

If you use large numbers in the thousands, they may become difficult to read:

The Value of the Control


When, or while, a spin button is being used, its text box displays a value: this
is the Value property. You can use this property to specify what value the
control would use at startup. It can be an integer or a decimal number but it
must be between the Minimum and the Maximum values. 

The Type of Value


By default, the numeric up-down displays natural numbers. Alternatively, you
can make the spin button display hexadecimal numbers. The type of numbers
displayed is controlled by the Boolean Hexadecimal property whose default
value is False, which means that it is primarily meant to display natural
numbers. If you prefer the control to display hexadecimal numbers, set this
property to True. Here is an example:
private void InitializeComponent()
{
nudCounter = new NumericUpDown();
nudCounter.Location = new Point(12, 12);
nudCounter.Minimum = 42.48M;
nudCounter.Maximum = 3822046.06M;

C# 3.0 Practical Learning II 567


nudCounter.Hexadecimal = true;

Controls.Add(nudCounter);
}

This would produce:

Displaying Decimal Numbers


By default, the numeric up-down control is made to display only natural
numbers. If you want it to display decimal numbers, use the DecimalPlaces
property to specify the number of decimal places on the right side of the
decimal separator which, in US English, is the period.

The Thousand Separator


If you want to make the control's numeric values easier to read, you can
display a symbol to separate the thousands. This characteristic can be set
using the Boolean ThousandsSeparator property whose default value is
False. If you want to display a symbol between thousands, set this property
to True. Here is an example:
private void InitializeComponent()
{
nudCounter = new NumericUpDown();
nudCounter.Location = new Point(12, 12);
nudCounter.Minimum = 42.48M;
nudCounter.Maximum = 3822046.06M;
nudCounter.ThousandsSeparator = true;

Controls.Add(nudCounter);
}

This causes the control to check the value used as the thousands separator in
the Control Panel of the computer that is using the application. The
thousands separator for US English is the comma ",". Here is an example:

The Incrementing Value


When using the spin button, the user clicks one of the arrows of the control
to increase or decrease the value. By default, the value increases or

C# 3.0 Practical Learning II 568


decreases by 1. If you want the value to augment by more than 1, set the
desired value using the Increment property. The value of this property can
be a natural or a decimal value (it is defined as System.Decimal). To set the
Increment value programmatically, you can use code as follows:

private void InitializeComponent()


{
nudCounter = new NumericUpDown();
nudCounter.Location = new Point(12, 12);
nudCounter.Minimum = 42.48M;
nudCounter.Maximum = 3822046.06M;
nudCounter.Increment = 125.82M;
nudCounter.ThousandsSeparator = true;

Controls.Add(nudCounter);
}

Applications:
Pledge Distribution

The Print Dialog Box


 

Introduction
One of the ways users print consists of sending the document to the printer.
To directly send a document to the printer, you need to make sure that the
control, whose value needs to be printed, supports printing. To accommodate
the users of your application, you can provide a menu item or a button they
would click. An example of such a button would be . To print, the user can
click this button. With this type of printing, when the user decides to print,
the whole document would be printed "as is", in color if the document is
colored and if the printer supports colors. If there is more than one printer,
the computer would use what is known as the default printer.

If you want users to be able to configure or customize the printing process,


Microsoft Windows provides a common dialog box called Print. Here is an
example:

C# 3.0 Practical Learning II 569


The Print dialog box allows a user to select a printer if more than one is
available. The user can decide either to print the whole document, to print a
range of pages, or to print a portion of the document that was previously
selected. The user can also decide on the number of copies to print from the
document, the range specified, or the selected portion. Furthermore, the user
can access the particular characteristics of the selected printer and specify
how the printer should perform the job. For example, if the selected printer
can print in color and the document is in color but the user wants to print in
black and white, he or she can specify this using the Properties button.

Providing a Printer
To provide the users with the ability to customize printing through the Print
dialog box, you can add a PrintDialog object from the Dialogs section of
the Toolbox to your form. The PrintDialog control is implemented through the
PrintDialog class of the System.Windows.Forms namespace. To
programmatically create a PrintDialog object, you can declare a variable of
type PrinterDialog. Here is an example:
using System;
using System.Drawing;
using System.Windows.Forms;

public class Exercise : Form


{
Button btnPrint;

public Exercise()
{
InitializeComponent();
}

C# 3.0 Practical Learning II 570


void InitializeComponent()
{
btnPrint = new Button ();
btnPrint.Location = new Point(12, 12);
btnPrint.Text = "&Print...";
btnPrint.Click += new EventHandler(btnPrintDocument);

Controls.Add(btnPrint);
}

void btnPrintDocument(object sender, EventArgs e)


{
PrintDialog dlgPrint = new PrintDialog();
}
}

public class Program


{
static int Main()
{
System.Windows.Forms.Application.Run(new Exercise());
return 0;
}
}

To present the Print dialog box to the user, you can call its ShowDialog()
method.

The Printing Process

The Document to Print


In order to print, the Print dialog box must be given a document to print. This
means that you must first prepare a document prior to printing. To support
this, the .NET Framework provides the PrintDocument class that is defined
in the System.Drawing.Printing namespace. This class is represented in

the Toolbox by the PrintDocument button . Based on this, to prepare a


document for printing, you can either add a PrintDocument object to your
project or declare a variable of type PrintDocument. Here is an example:
using System;
using System.Drawing;
using System.Windows.Forms;
using System.Drawing.Printing;

public class Exercise : Form


{
Button btnPrint;

C# 3.0 Practical Learning II 571


public Exercise()
{
InitializeComponent();
}

void InitializeComponent()
{
btnPrint = new Button ();
btnPrint.Location = new Point(12, 12);
btnPrint.Text = "&Print...";
btnPrint.Click += new EventHandler(btnPrintDocument);

Controls.Add(btnPrint);
}

void btnPrintDocument(object sender, EventArgs e)


{
PrintDialog dlgPrint = new PrintDialog();
PrintDocument docPrint = new PrintDocument();
}
}

After creating the document to print through a PrintDocument object, you can
associate it with a PrintDialog. To support this, the PrintDialog class is
equipped with the Document property. To specify the object that would carry
the printing, you can assign the PrintDocument object to the
PrintDialog.Document property. Here is an example:

System.Void btnPrint_Click(System.Object sender,


System.EventArgs e)
{
PrintDialog dlgPrint = new PrintDialog;
PrintDocument docPrint = new PrintDocument;

dlgPrint.Document = docPrint;
dlgPrint.ShowDialog();
}

A document to print can be made of only one or many pages. Each page has
a number of characteristics. The characteristics of a page are controlled by
the PrintDocument.PageSettings property which itself is based on the
PageSettings class. The PageSettings class is defined in the
System.Drawing.Printing namespace. This class holds the dimensions of
the page, the values of the margins applied on the page, the tray that would
supply the paper (since some printers have many trays), the printer
resolution, whether the page would be printed in color or black and white,
whether the page would be printed in Portrait or Landscape orientation, etc.
If you don't want to specify these characteristics, you can set the
PrintDocument.PageSettings property to DefaultPageSettings.

If you know the name of the document to be printed, you can assign it to the
PrintDocument.DocumentName property. Here is an example:

C# 3.0 Practical Learning II 572


void btnPrintDocument(object sender, EventArgs e)
{
PrintDialog dlgPrint = new PrintDialog();
PrintDocument docPrint = new PrintDocument();

dlgPrint.Document = docPrint;
dlgPrint.ShowDialog();
}

To actually print the document, you can call the PrintDocument.Print()


method. Its syntax is:
public void Print();

Events Related to Printing


When the PrintDocument.Print() method is called, the printing process
would start by firing the BeginPrint event but this event occurs before the
first page is printed. The BeginPrint event is of type PrintEventArgs
which does not hold any particular information, especially for the BeginPrint
event. This event allows you to take some early actions, if necessary, before
the printer receives the job.

Once the printer is ready, the application would then need to know what
needs to be printed on the paper. At this time, the PrintPage event is fired.
The PrintPage event is of type PrintPageEventArgs. The
PrintPageEventArgs class allows you to fully customize the page of the
document to be printed. For example, it is equipped with a Graphics
property that allows you to "draw" anything you want on the paper. The
PrintPageEventArgs class also allows you to get the location and
dimensions of the area to be printed. This is represented by the PageBounds
property, which produces a Rectangle object.

Once the PrintDocument object is ready, you must pass it to the Print dialog
box. To do that, assign the name of the PrintDocument variable to the
PrintDialog.Document property.

The Printer Settings


In the above example, we saw a somewhat simplistic way of making the Print
dialog box available to the user. This dialog box offers many options defined
as the Printer Settings. To support the various options of a Print dialog box,
the PrintDialog class is equipped with a property called PrinterSettings,
which itself is defined from the PrinterSettings class, which holds all
possible characteristics of a printer.

The first option presented to the user is the name of the printer to be used.
Because there can be many printers available to the user, the printers are
presented as a combo box:

C# 3.0 Practical Learning II 573


The available printers may also be presented as a list view:

The Name combo box in the Printer section or the Select Printer list view
allows the user to select the printer that will handle the job. If you are writing
a universal application and cannot predict what printer(s) the user would

C# 3.0 Practical Learning II 574


have, you would not be concerned with this characteristic. If you are writing
an application for a special company or you are creating a particular
application and you know for sure what printer should be used to print the
current document, then you can specify the printer to use. To do this, assign
the (exact) name of the printer to the PrinterSettings.PrinterName
property. On the other hand, if for some reason you want to know what
printer the user selected to print the document, you can get the value of this
PrinterName property.

Under the Name combo box, the labels provide the status of the selected
printer (whether it is ready or not), the type of printer (such as its
manufacturer), its location (such as where in the building the printer is
located; the person who installed the printer or may have provided this
printer), and an optional comment (this information is created by the person
who installed the printer or it can be changed in the printer's properties).

After selecting the printer, the user can access the properties of that
particular printer. Different printers support different options. To configure
the printed paper based on the selected printer, the user can click either
Properties or Preferences. This opens the Document Properties or the Printing
Preferences dialog box. The content of this dialog box (highly) depends on
the printer that was selected but some characteristics are shared among
printers.

On the lower-right side of the Printer section or of the Select Printer section,
there is a check box labeled Print To File. When this check box is checked, the
document is transformed into a file rather than being printed. In this case, if
the user clicks OK or Print, a dialog box would come up, asking the user to
specify the path and a name for the new file that will be created. The
appearance of that dialog box depends. Here is an example:

If you want the Print To File check box to be checked, set the
PrinterSettings.PrintFoFile Boolean property to true. Its default value
is false, which lets the user decide whether to check it or not.

C# 3.0 Practical Learning II 575


After selecting the printer and deciding whether to physically print or to only
create a printed file, the user can click OK.

If the document is made of only one page, it would be printed. If the


document contains more than one page, the user may want to print only one
page, a range of pages, or all pages. The user can also select a section in the
document and print only that section. This decision is made using the Page
Range section. This section provides four radio buttons. The first radio button
labeled All is selected by default and allows the user to print the whole
document. By default, the second radio button is disabled. If the user had
selected a section of the document to print, then the second radio button,
labeled Selection would be enabled:

This allows the user to still specify whether to print the whole document or
only the section that was selected. If the document contains more than one
page, the user can navigate to a particular page and decide to print only that
page using the Current Page radio button. Again, if the document contains
more than one page, the user can specify a range of pages to print. All these
options are usually left up to the user. On the other hand, if you want to
specify the range of pages to print, you can use the
PrinterSettings.FromPage and the ToPage properties. If you want to
specify the limits of ranges allowed to the user, use the MinimumPage and the
MaximumPage properties.

C# 3.0 Practical Learning II 576


On the right side of the Page Range section, a spin button allows the user to
specify the number of copies to make when printing. If you want to specify
this number by default, assign the desired value to the Copies property. If
the user (or you) set this number to a value higher than 1, then the printed
papers can be collated or not. This is specified using the Collate check box. If
you want to programmatically collate the pages or not, change the Boolean
value of the Collate property.

The Save Dialog Box


 

Description
Most of the applications allow users to open or display an empty document.
This indicates that such an application expects the user to create a document.
Once a document has been created, a user would usually want to store its
contents on a medium (hard drive, floppy disk, etc). Microsoft Windows
provides a common dialog box for this purpose: The Save As dialog box:

The primary role of the Save As dialog box is to allow users to store a file on
the hard drive of the computer, on a portable medium such as a floppy disk,
or on a network drive. To make this efficient and complete, the user must
supply two valuable pieces of information: the location and the name of the
file. The location of a file is also known as its path.

C# 3.0 Practical Learning II 577


The name of a file follows the directives of the operating system. On MS DOS
and Windows 3.X, it had to be in an 8.3 format. The actual name had to have
a maximum of 8 characters with restrictions on the characters that could be
used. The user also had to specify three characters after a period. The three
characters, known as the file extension, were used by the operating system to
classify the file. That was all necessary for those 8-bit and 16-bit operating
systems.

Various rules have changed. For example, the names of folders and files on
Microsoft Windows >= 95 can have up to 255 characters. The extension of
the file is mostly left to the judgment of the programmer but most files are
still using extensions. Applications can also be configured to save different
types of files; that is, files with different extensions.

To use the Save As dialog box, users usually click an item under the File
menu. Here is how it works for most regular applications. The user creates a
new document. If the user wants to save the file, he or she can click File ->
Save. If the document was not previously saved, the application would call
the Save As dialog box. If a document is displaying, whether it was saved
previously or not, the user can also click File -> Save As... which also would
call the Save As dialog box.

Two objects are particularly important on the Save As dialog box: The Save In
combo box and the File Name text box or combo box (the File Name box is
made of a combo box to make it user-friendly but over all, users hardly use
the list side of this combo box). Since Windows 95, the user does not have
to specify an extension if the programmer makes it easy. To help with this,
the Save As dialog box is equipped with a Save As Type combo box. This
combo box allows the user to select one of the extensions. The available
extensions have to be created by the programmer so the user can select from
a preset list. If the programmer neglects this, the user would have no
extension to select from. Although the file can still be saved, the operating
system would not associate it with a known type of file. Therefore, if you
specify a series of extensions, the user can select one of these and, in the File
Name box, he or she can simply type a name for the file.

If the user does not specify an extension, the operating system would
associate the extension of the Save As Type combo box. Users of regular
commercial applications, such as word processors, spreadsheet programs, or
graphical applications, etc, are usually trained not to care about the
extensions and let the application deal with that detail. In some other
circumstances, the users must pay close attention to the extension they give
a file. This is common on web development or graphics design because
various file extensions are supported and overall produce the same end
result.

After working on a Save As dialog box, users can click Save or press Enter,
which would validate their entry. To change their mind, regardless of what
they did on the Save As dialog box, users can click Cancel or press Esc, which

C# 3.0 Practical Learning II 578


would dismiss the dialog box and ignore what they did (in reality, some
actions cannot be ignored, such as creating a new file or folder inside of the
Save As dialog box, deleting, cutting, or pasting files, etc; but if the user
clicked Cancel or pressed Esc, the new file would not be saved).

Save As Dialog Box Creation


To make a Save As dialog box available to your application, on the Toolbox,
you can click the SaveFileDialog button and click the form. To
programmatically provide this dialog box, you can declare a SaveFileDialog
variable and initialize it using the class's default constructor as follows:
using System;
using System.Windows.Forms;

public class Exercise : Form


{
private SaveFileDialog sfd;

public Exercise()
{
InitializeComponent();
}

void InitializeComponent()
{
sfd = new SaveFileDialog();
}
}

public class Program


{
public static int Main()
{
Application.Run(new Exercise());

return 0;
}
}

The SaveFileDialog class inherits from the FileDialog class from which it
gets most of its characteristics and behaviors.

C# 3.0 Practical Learning II 579


Characteristics of the Save As Dialog
Box
 

The File Extension


To make sure that your application can open the allowed types of files,
depending on your goals, you should create a list of extensions that you want
the users to be able to open. The allowed extensions form a group called a
filter. The filter is like a funnel that selects the good items. For a text-based
application, you may allow only text files, that is, files with a txt extension.
For a rich text-based application, you may allow only Rich Text Format files,
which are files with rtf extension. On the other hand, if you are creating an
application for web files, you can allow as many file extensions as necessary,
such as htm, html, php, asp, etc.

As you may realize, text files or web files are all text-based files. This means
that if you create a text-based or rich-text based application, you should allow
the users to decide whether the file they are trying to open can be "read" by
a text-based control. To provide this ability, you can specify an unknown
extension specified as All Files.

The Filter
To create a list of allowable extensions for your FileSaveDialog object, you
can use the Filter property from the Properties window. At run time, you
can create a list of file extensions as a string. If the Save As dialog box will
need only one extension, you can create the string using the following syntax:
Prompt|Extension

The Prompt is a section that defines what the user would see in the Save As
Type combo box. An example would be 24-bit Bitmap. Such a string does
not let the user know what actual extension the file would use. Therefore, as
a courtesy, you can specify, between parentheses, the extension that would
be applied if this extension is used. The Prompt can be 24-bit Bitmap
(*.bmp). In this case, the extension used would be bmp. The asterisk * lets
the user know that whatever is provided as the file name would be used in
place of the asterisk. The period indicates the separation from the file to its
extension. This means that the characters on the left of the period would be
the file name, the characters on the right side of the period would be used as
the actual file extension.

C# 3.0 Practical Learning II 580


To specify the extension that the operating system would use to associate to
the file, you provide a second part of the string as Extension. In Microsoft
Windows, most extensions are made of three characters. Some applications
use a 2-letter extensions (for example Perl files have a pl extension) and
some others use 4 letters (such as html for some HTML files). This depends
on the programmer (or the company that is publishing the application). An
example of a string as an extension is:
24-bit Bitmap (*.bmp)|*.bmp

If you want to provide various extensions to your Save As dialog box, you can
separate them with a | symbol. An example would be:
HTML Files (*.htm)|*.htm|Active Server Pages (*.asp)|*.asp|Perl
Script (*.pl)|*.pl

If you added a FileSaveDialog control to a form, as mentioned earlier, you can


type the filter string in the Filter field of the Properties window. If your
programmatically creating the dialog box, you can assign the string to the
Filter property. Here is an example:

public class Exercise : Form


{
private SaveFileDialog sfd;

public Exercise()
{
InitializeComponent();
}

void InitializeComponent()
{
sfd = new SaveFileDialog();
sfd.Filter = "HTML Files (*.htm)|*.htm|" +
"Active Server Pages (*.asp)|
*.asp|" +
"Apache Files (*.php)|*.php|"
+
"Perl Script (*.pl)|*.pl|" +
"All Files|";
}
}

This would produce:

C# 3.0 Practical Learning II 581


The Filter Index
A filter organizes its extensions and categories as indexes. The above filter
has the following indexes:

Index 1 = HTML Files (*.htm)


Index 2 = Active Server Pages (*.asp)
Index 3 = Apache Files (*.php)
Index 4 = Perl Script (*.pl)
Index 5 = All Files;

After creating a filter, when the dialog box comes up, the Save As Type
combo box displays the first index of the filter. If you want, instead of
displaying the first index by default, you can specify another index. To specify
the desired index at design time, change the value of the FilterIndex field
in the Properties window. To programmatically specify it, assign a value to the
FileSaveDialog.FilterIndex property. Here is an example:

public class Exercise : Form


{
private SaveFileDialog sfd;

public Exercise()
{

C# 3.0 Practical Learning II 582


InitializeComponent();
}

void InitializeComponent()
{
sfd = new SaveFileDialog();
sfd.Filter = "HTML Files (*.htm)|*.htm|" +
"Active Server Pages (*.asp)|
*.asp|" +
"Apache Files (*.php)|*.php|"
+
"Perl Script (*.pl)|*.pl|" +
"All Files|";
sfd.FilterIndex = 3;
}
}

Once you know the types of files that your application will be dealing with,
you can make your dialog box friendly by displaying the most likely extension
for a document created using your application. For example, if you create a
text-based application, users are more likely to create a text file with it. If you
create a rich text-based application, users are more likely to create a Rich
Text Format file with it. This most likely extension is known as the default
extension, it allows the user not to provide an extension in the most likely
cases when saving a file. By simply providing a file name and clicking Save,
the operating system would associate the file with the default extension. Of
course, if you create a filter, the user can specify a desired allowed extension.

The Default Extension


To specify the default extension for your FileSaveDialog object, type the
desired extension in the DefaultExt field of the Properties window. If you
had created a Filter and if you provide a default extension for a
FileSaveDialog object, make sure it is one of the file extensions specified in
the Filter list. To programmatically specify a default extension, assign it to
the DefaultExt property of your FileSaveDialog variable. Here is an
example:
public class Exercise : Form
{
private SaveFileDialog sfd;

public Exercise()
{
InitializeComponent();
}

void InitializeComponent()
{
sfd = new SaveFileDialog();
sfd.Filter = "HTML Files (*.htm)|*.htm|" +

C# 3.0 Practical Learning II 583


"Active Server Pages (*.asp)|
*.asp|" +
"Apache Files (*.php)|*.php|"
+
"Perl Script (*.pl)|*.pl|" +
"All Files|";
sfd.FilterIndex = 3;
sfd.DefaultExt = "htm";
}
}

Displaying the Dialog Box


Once the OpenFileDialog object is ready, to display it to the user, call its
ShowDialog() method. Here is an example:

using System;
using System.Windows.Forms;

public class Exercise : Form


{
private SaveFileDialog sfd;

public Exercise()
{
InitializeComponent();
}

void InitializeComponent()
{
sfd = new SaveFileDialog();
sfd.Filter = "HTML Files (*.htm)|*.htm|" +
"Active Server Pages (*.asp)|
*.asp|" +
"Apache Files (*.php)|*.php|"
+
"Perl Script (*.pl)|*.pl|" +
"All Files|";
sfd.FilterIndex = 3;
sfd.DefaultExt = "htm";

sfd.ShowDialog();
}
}

public class Program


{
public static int Main()
{
Application.Run(new Exercise());

return 0;
}
}

C# 3.0 Practical Learning II 584


Microsoft Windows operating systems, especially since Windows 9X, are
configured to have a default folder in which users are most likely to save their
files. On Windows 9X, it is C:\My Documents. On Windows NT, it is usually
specified by the network administrator. On Windows 2000 and Windows XP,
it uses a more customized scenario. These settings are known to the
operating system and you will usually not be concerned with them. In some
circumstances, if you want to specify the folder in which the users should
save their files by default, you can provide it using the InitialDirectory
property. This directory usually ends with \My Documents. If you want to find
the path to the My Documents for a user, you can call the
Environment.GetFolderPath() method and pass it the Personal member
of the Environment.SpecialFolder enumerator. The syntax of the
GetFolderPath() method is:

public static string GetFolderPath(SpecialFolder folder);

Here is an example:
private System.Void button1_Click(System.Object sender,
System.EventArgs e)
{
string strMyDocuments =

Environment.GetFolderPath(Environment.SpecialFolder.Personal);
this.textBox1.Text = strMyDocuments;
}

Once again, most of the time, you will not be concerned with this issue if you
are creating an application for any user.

Probably the most important issue users care about, as far as they are
concerned, is a name for the file they are trying to save. Users know that
they can set the name of the file in the File Name box. To make this action a
little faster, you can provide a default name for a file in case a user does not
want to specify a file name. This is done by typing a name in the FileName
field of the Properties window. In practicality, the FileName value is the
string that displays in the File Name box of the Save As dialog box.

By default, when the Save As dialog box comes up, it displays "Save As" on
its title bar. If you want a different caption, set the desired string in the Title
field of the Properties window or assign a string to the
FileSaveDialog.Title property.

C# 3.0 Practical Learning II 585


Windows Control: The Text Box
 

Introduction to Text Boxes

Introduction
A text box is a Windows control used to get or display text to the user. At its
most regular use, a text box serves as a placeholder to fill out and provide
information. Such a use is common on employment applications, login
dialog boxes, forms, etc. Like most other controls, the role of a text box is not
obvious at first glance; that is why it should be accompanied by a label that
defines its purpose.

From the user’s standpoint, a text box is named after the label closest to it.
Such a label is usually positioned to the left or the top side of the text box.
From the programmer’s point of view, a text box is a placeholder used for
various things. For example, you can show or hide it as you see fit. You can
also use it only to display text without allowing the user to change it.

Creating a Text Box


To create a text box, from the Common Controls section of the Toolbox, you
can click TextBox and click the form. The text box is based on the
TextBox class. This means that you can use this class to dynamically
create a text box and add it to your application. The text box control is
based on the TextBox class whose immediate parent is TextBoxBase. Like
every .NET Framework class, it has a constructor that can be used to
dynamically create the control. The TextBoxBase class provides other
methods derived from the control’s parent or from ancestor classes.

Using the Text of a Text Box

Introduction
As a control primarily meant to display text, like a label, the text box shares
many of the characteristics of a label: text alignment, font, color, etc.

C# 3.0 Practical Learning II 586


The most important aspect of a text box is its text, whether it is displaying or
requesting it. This is the Text property. When you add a text box control to a
form or other container, by default, it is left empty. If you want the control to
display some text when the form launches, type a string in the Text property
field in the Properties window.

After creating a text box, it may be empty, the user can start typing in it to fill
it with text. You can programmatically assign it a string to occupy it. Another
way you can put or add text to the control is to paste the content of the
clipboard, using text from another control. The syntax of the Paste() method
is:
public void Paste();

At any time, to know the length of the text in the control, you can retrieve the
value of the TextLength property, which is of type int.

Selecting Text
The selection of text from a text box control can be performed either by you
or by a user. To select part of the text, you can specify the starting point
using the SelectionStart property, which is of type int. After the starting
position, you can specify the number of characters to include in the selection.
This is done using the SelectionLength property, which is of type int. The
SelectionStart and the SelectionLength properties allow you to
programmatically select text. The user, on the other hand, also knows how to
select part of the text of the control. These operations can also be performed
using the Select() method of the TextBox class. Its syntax is:
public void Select(int start, int length);

Alternatively, the user may want to select the whole content of the control.
To programmatically select the whole text of a text box control, call the
SelectAll() method. Its syntax is:

public void SelectAll();

When  some text has been selected in the control, to get that text, you can
retrieve the value of the SelectedText property, which is a handle to
String.

Operations on Text
After the text, in part or in whole, has been selected, you or the user can
manipulate it. For example, you can copy the selection to the clipboard. This
is done using the Copy() method. Its syntax is:
public void Copy();

C# 3.0 Practical Learning II 587


To delete part of the text, the user can cut it. You can programmatically do
this using the Cut() method. Its syntax is:
public void Cut();

To delete the whole contents of the text box, you can call the Clear()
method. Its syntax is:
public void Clear();

Any operation performed on the text box can be undone using the Undo()
method whose syntax is:
public void Undo();

To prevent an undo operation, call the ClearUndo() method. Its syntax is:
public void ClearUndo();

Characteristics of Text Boxes

Mnemonics
As mentioned already, a text box should be accompanied by a label that
indicates what it is used for. To support this relationship, the Label control
provides various properties. An accelerator character is a symbol of the label
that provides easy access to its text box. On the label, such a character is
underlined. An example would be First Name. The idea is that, if the user
presses the Alt key in combination with the label’s underlined character, the
text box it accompanies would receive focus.

To create an accelerator key, choose one of the label’s characters and


precede it with an ampersand character when setting its caption. An example
would be &First Name. If you want a label to display the accelerator character
instead of a plain ampersand, set the label’s UseMnemonic property to true,
which is already its default value. If you set it to true but need to display an
ampersand, type two & characters where the ampersand would be shown.

The UseMnemonic property of a label is only used to indicate that the label
would display an accelerator character and the & symbol typed on the label
creates that accelerator character. To indicate which text box would receive
focus when the accelerator character of the label is invoked, you must make
sure you establish an appropriate tab sequence using the Tab Order menu
item from the main menu or using the combination of TabStop/TabIndex
properties. Typically, the label should have a Tab Order or TabIndex value
that is just - 1 of that of the control it serves.

C# 3.0 Practical Learning II 588


The Read-Only Attribute
By default, a newly created text box is used to both display and receive text
from the user. If you want the user to read text without being able to change
it, set the ReadOnly Boolean property to True. Its default value is false.

Auto-Completing a Text Box


If a text box allows the user to enter text in it, the user can click the control
and start typing. If a certain text box usually receives some known or
common strings, you can assist the user with completing the entry. The
TextBox class supports this with three properties.

If you want to assist the user with completing the string entered in a text
box, first specify where the necessary strings will come from. You have two
options. You can use the AutoCompleteSource property, that is based on the
AutoCompleteSource enumeration. Its members are: None,
RecentlyUsedList, FileSystem, FileSystemDirectories, HistoryList,
ListItems, AllSystemSources, AllUrl, and CustomSource.

If you want to specify your own-created list of items, use the


AutoCompleteCustomSource property. At design time, to create a list of
strings, access the Properties window for the text box. In the Properties
window, click the ellipsis button of the AutoCompleteCustomSource field to
open the String Collection Editor. Enter the strings separated by a hard
Return, and click OK.

After specifying the source of the list that will assist the user to complete the
entry of the text box, set it AutoCompleteMode property. This property is
based on the AutoCompleteMode enumeration that has four members. None
is the default value. 

Character Casing
A text box can be configured to display only lowercase characters, only
uppercase characters, or a mix. This characteristic is controlled by the
CharacterCasing property, which is an enumerator that holds the same
name. The default value of this property is Normal, which indicates that the
control can use a mix of lowercase and uppercase characters. If you set this
property to Lower, all existing characters, if any, in the control would be
converted to lowercase and all future characters typed in the control would be
automatically converted to lowercase. If you set this property to Upper, all
existing characters, if any, in the control would be converted to uppercase
and all future characters typed in the control would be automatically
converted to uppercase.

Character Password

C# 3.0 Practical Learning II 589


Text typed in a text box appears with its corresponding characters unless you
changed the effect of the CharacterCasing property from its default Normal
value. This allows the user to see, and be able to read, the characters of the
control. If you prefer to make the characters un-readable, you have two
options.

The operating system uses a default character it uses to hide the contents of
a text box. If you want to use that character, set the
UseSystemPasswordChar property to true. If you prefer to specify your own
character, you can use the PasswordChar property. Although this property is
a char type of data, changing it actually accomplishes two things:

 If you type a character in its field in the Properties window, for example
if you type *, any character typed in it would be un-readable

 Any character in the control would be replaced by the value of this


property. You can use any alphabetic character or digit to represent the
characters that would be typed but you must provide only one character

The Multi-Line Text Box

Introduction
The regular text box is meant to display a piece or one line of text. If the user
enters text and presses Enter, nothing particular happens. If the user enters
text and presses Tab, the focus moves to the next control in the tab
sequence. You may want to create an application that goes further than the
one-line limit. For example, if you have used Notepad, you would know that it
shares the font characteristics of a text box but it also allows some text
navigation features that require more than one line. You can create such an
application based on the text box control.

Creating a Multi-Line Text Box


The TextBox control is equipped with one particular property that, when
considered, changes the control tremendously. This property is called
Multiline. Multiline is a Boolean property whose default value is false. If
it is set to a true value, it allows the control to display multiple lines of text,
unlike the normal text box that can display only one line.

Characteristics of a Multi-Line Text Box

C# 3.0 Practical Learning II 590


Introduction
The multi-line text box shares all of the properties of the single-line text box.
These include the read-only attribute, the character casing, and the password
options. Although these properties are valid, some of them may not be
suitable for a multi-line text box, such as applying a password character to
hide the text, trying to auto-complete a string while the user is typing it, etc.
This is why, in most cases, we will tend to consider the single-line and the
multiple line objects are separate controls.

The Lines of Text


By default, when you add a new text box to your form, it appears empty.
When the application comes up, the user mostly reads and/or enters text in
the multi-line text box when interacting with the control. At design time, you
can set the text that would display when the multi-line text box comes up. To
enter this text, in the Properties window, click the Lines field to reveal its
ellipsis button that allows you to open the String Collection Editor. Type the
desired text and click OK. On the other hand, after the user has entered some
text or a few lines of text in the control, it holds these lines. The lines of text
of a text box are stored in an array represented by a property named Lines.
This means that, at run time, you can create an array of lines of text and
assign it to the text box. Or, to get the lines of text of the control, you can
retrieve the value of the Lines property.

The Modified Attribute


When a multi-line text box opens, the compiler registers the content of the
control. If the user has the ability to change the text in the control and if the
user changes it, the compiler flags the control as Modified. This allows you
to take actions. You can acknowledge this by programmatically setting the
Modified property to true. If another control or some other action alters the
contents of the multi-line text box, you can make sure that this property
reflects the change. You can change this programmatically as follows:
private void button1_Click(object sender, EventArgs e)
{
textBox1.Modified = true;
}

The Maximum Length of Text


The multi-line text box allows the user to enter up to 32767 characters. If you
want to limit the maximum number of characters that the user can enter to a
value lower than this, you can use the MaxLength property at design time.
You can also change this programmatically. Here is an example:
private void button1_Click(object sender, EventArgs e)
{

C# 3.0 Practical Learning II 591


textBox1.MaxLength = 1020;
}

Using the Enter Key


If the control will be used to enter text, the user can press Enter at the end of
a line to move to the next line. This ability is controlled by the Boolean
AcceptsReturn property. By default, this property is set to False because
this control is primarily created from a normal single-line TextBox control that
has no formal action to take when the user presses Enter. If you are creating
a multi-line text box and you expect your users to perform some type of text
editing, you certainly should allow them to press Enter to move to the next
line. Therefore, in most cases, when creating a multi-line text box, you should
set its AcceptsReturn property to True. To set it programmatically, assign
the desired value to the AcceptstReturn property. Here is an example:
private void button1_Click(object sender, EventArgs e)
{
textBox1.AcceptsReturn = true;
}

Using the Tab Key


The user is accustomed to pressing Tab to insert tab characters in the text.
By default, when the user presses Tab when interacting with your application,
the focus moves from one control to the next, following the TabIndex values
of the form. Even when using a multi-line text box to perform text editing, if
the user presses Tab, the focus would switch to another control or to the
form. If you want a multi-line text box to receive focus when the user presses
the Tab key, set the AcceptTab property from False (the default), to True.

When entering text in a multi-line text box control, the characters start on the
left side of the multi-line text box and are subsequently added on the right
side. The ability to align text is controlled by the TextAlign property. For a
multi-line text box control, the alignment is configured using the
HorizontalAlignment enumerator.

Wrapping Text
As the user enters text in a multi-line text box box, the compiler considers
that a paragraph starts from the user typing a character until he or she
presses Enter. Therefore, a paragraph could be an empty space, a character,
a word, a line of text, a whole page or an entire book. Depending on the
width of the multi-line text box control, the text is incrementally added to the
right side of each previous character. If the caret gets to the right border of
the control, the text automatically continues to the next line, although it is still
considered as one paragraph. To start a new paragraph, the user has to press
Enter. The ability for the text to continue on the next line when the caret
encounters the right border of the multi-line text box is controlled by the

C# 3.0 Practical Learning II 592


WordWrap property whose default Boolean value is set to true. If you do not
want text to wrap to the subsequent line, set the WordWrap property to false.
You can also set it programmatically as follows:
private void button1_Click(object sender, EventArgs e)
{
textBox1.WordWrap = false;
}

Using Scroll Bars


When a text box has been configured to hold multiple lines and once its text
becomes too long, part of the content could become hidden. To show the
hidden part, the control should be equipped with scrollbars so the user can
navigate up and down, left and right. To support the display of scrollbars, the
TextBox class is equipped with the ScrollBars property. You can specify
the option of this property at either the design time or the run time or both.

The TextBox.ScrollBars property is based on the ScrollBars


enumeration that has four members:

 None: This is the default value and its means that the text box would not
display any scrollbar

 Vertical: This option specifies that the text box should display a vertical
scroll bar when its content becomes too long

 Horizontal: This is valid only if the WordWrap property is set to false. In


this case, the text box would display a horizontal scroll bar
 Both: This allows displaying both the vertical and the horizontal scrollbars

Methods to Manage a Multi-Line Text Box


The multi-line text box control is based on the TextBox class. To dynamically
create a multi-line text box, declare a TextBox variable and use its default
constructor to initialize it. The other operations the user can perform on a
multi-line text box can be controlled by methods such as Undo(), Cut(),
Copy(), Paste(), Clear() or SelectAll() that we reviewed for the text
box control and they function the same.
Here are examples: 

private void mnuEditUndo_Click(object sender, EventArgs e)


{
this.txtNotice.Undo();
}

 
private void mnuEditCut_Click(object sender, EventArgs e)

C# 3.0 Practical Learning II 593


{
this.txtNotice.Cut();
}

 
private void mnuEditCopy_Click(object sender, EventArgs e)
{
this.txtNotice.Copy();
}

 
private void mnuEditPaste_Click(object sender, EventArgs e)
{
this.txtNotice.Paste();
}

Application
Elementary Addition

Payroll Processing

Windows Controls: The Track Bar


 

Introduction
A track bar is a control used to slide a small bar or pointer, also called a
thumb, along a continuous line. In the following dialog box, there is an
example of a track bar under Adjust the slider...:

C# 3.0 Practical Learning II 594


To use the track bar, the user can drag the thumb in one of two directions.
This changes the position of the thumb. The user can also click a position
along the control line to place the thumb at a desired location. Alternatively,
when the track bar has focus, the user can use the arrow keys to move the
thumb.

As far as appearances are concerned, there are two types of track bars,
depending on the orientation: horizontal or vertical. Here is an example of a
vertical track bar on the left side of Medium:

C# 3.0 Practical Learning II 595


A track bar is configured with a set of values from a minimum to a maximum.
Therefore, the user can make a selection included in that range. Optionally, a
track bar can be equipped with small marks called ticks. These can visually
guide the user for the available positions of the thumb.

A track bar can be used as a progress control to help the user monitor an
activity. A track bar also allows the user to specify a value that conforms to a
range. When equipped with small indicators, also called ticks, a track bar can
be used to control exact values that the user can select in a range, preventing
the user from setting just any value.

Creating a Track Bar


To support track bars, the .NET Framework provides the TrackBar class. At
design time, to add a track bar to your application, from the Toolbox, you
can click the TrackBar button and click the form or a container. The
TrackBar class is derived from the Control class. To programmatically
create a track bar, declare a variable of type TrackBar, use the new operator
to allocate memory for the variable, and add it to the Controls property of its
parent. Here is an example of creating a track bar:
using System;
using System.Drawing;
using System.Windows.Forms;

C# 3.0 Practical Learning II 596


public class Exercise : System.Windows.Forms.Form
{
TrackBar tbrSlider;

public Exercise()
{
InitializeComponent();
}

private void InitializeComponent()


{
tbrSlider = new TrackBar();

Controls.Add(tbrSlider);
}
}

public class Program


{
static int Main()
{
System.Windows.Forms.Application.Run(new Exercise());
return 0;
}
}

This would produce:

Characteristics of a Track Bar


 

The Orientation
After placing a TrackBar control on a form or other container, by default, its
assumes a horizontal position. The position of the track bar is controlled by
Orientation property implemented through the Orientation enumeration
that has two members. To change the direction of the control, on the
Properties window, set the Orientation property to the desired value. For
example, to make it vertical, change the field from Horizontal to Vertical.

C# 3.0 Practical Learning II 597


To change this property at runtime, assign the desired value to the property.
Here is an example:

private void InitializeComponent()


{
tbrSlider = new TrackBar();
tbrSlider.Location = new Point(12, 12);

tbrSlider.Orientation = Orientation.Vertical;
Controls.Add(tbrSlider);
}

This would produce:

The dimensions of the track bars we have displayed so far don't appear
practical. This is because we were using the default values. Like every
control, the track bar has default dimensions and like many controls, these
default values are usually not suitable. This means that every time you create
a track bar, make sure you specify either its Size property or its Width and
its Height properties. Here is an example:
private void InitializeComponent()
{
tbrSlider = new TrackBar();
tbrSlider.Location = new Point(12, 12);
tbrSlider.Width = 180;

Controls.Add(tbrSlider);
}

This would produce:

The Value of a Track Bar


As mentioned already, to use the track bar, the user must change the position
of the thumb. To change this position, the user can drag the thumb, click the
slider line, press one of the arrow keys, or press the Page Up or Page Down
keys. As the user drags the thumb, the control fires a Scroll event. This

C# 3.0 Practical Learning II 598


event is of type EventArgs. Because this is the default event of the control,
to generate its skeleton code, you can double-click the track bar on the
control

When the user drags the thumb, the control holds a new value known as the
Value property. You also can assign a value to this property to change the
position of the thumb. The value of the Value property must be an integer.
After the user has changed it, to know the value of the track bar, you can
access its Value property. Here is an example:
private void InitializeComponent()
{
tbrSlider = new TrackBar();
tbrSlider.Location = new Point(12, 12);
tbrSlider.Width = 180;

tbrSlider.Value = 6;

Controls.Add(tbrSlider);
}

This would produce:

1. Return to the form and double-click the right track bar

2. Return to the form

The Maximum and the Minimum Values


However the user moves the thumb, it must assume a value between the
limits allowed on the control. The Minimum property is the lowest value that
the thumb can assume within the track. The Maximum value controls the
opposite. The user is allowed to slide only between these two values. These
two properties are set in the Properties window using their respective fields.
By default, the minimum value is set to 0 and the maximum is 10. To change
the minimum or maximum values programmatically, assign the desired value
to the appropriate property. Here is an example:
private void InitializeComponent()
{
tbrSlider = new TrackBar();
tbrSlider.Location = new Point(12, 12);
tbrSlider.Width = 480;

tbrSlider.Minimum = 8;
tbrSlider.Maximum = 140;

C# 3.0 Practical Learning II 599


tbrSlider.Value = 86;

Controls.Add(tbrSlider);
}

This would produce:

You can also set the minimum and the maximum values by calling the
TrackBar.SetRange() method. Its syntax is:

public void SetRange(int minimum, int maximum);

The first argument is the same as the Minimum property and the second
argument is the same as the Maximum property. Here is an example:
private void InitializeComponent()
{
tbrSlider = new TrackBar();
tbrSlider.Location = new Point(12, 12);
tbrSlider.Width = 480;

tbrSlider.SetRange(8, 140);

tbrSlider.Value = 86;

Controls.Add(tbrSlider);
}

Always make sure that the minimum value is lower than the maximum. This
safe measure will allow you to better control the current value of the control.
At design time, if you set the Minimum property to a value higher than that of
the Maximum, for example setting Minimum to 66 while Maximum=10, the
value of the Maximum would be set to that of the Minimum. In this case, both
properties would have the same value. This makes the control unusable: if
the Minimum and the Maximum properties hold the same values, the user
cannot move the thumb. In the same way, at run time, avoid assigning
unpractical values to these properties.

The Ticks of a Track Bar


A track bar is equipped with small bars “|” that serve as indicators of the
position occupied by the thumb. These bars are called ticks. The ticks are
positioned at same distances from each other. The number of ticks available
on a track bar, or the number of ticks you can see, depend on the difference
between the Minimum and the Maximum values The higher the Maximum -

C# 3.0 Practical Learning II 600


Minimum difference, the more ticks available. The lower this value, the fewer
the ticks but this should not be the reason you use a lower Minimum or a
higher Maximum.

The Tick Frequency


If the difference between the Maximum and the Minimum properties causes
the control to display too many ticks. Consider the following example:
private void InitializeComponent()
{
tbrSlider = new TrackBar();
tbrSlider.Location = new Point(12, 12);
tbrSlider.Width = 400;
tbrSlider.SetRange(8, 255);
tbrSlider.Value = 125;

Controls.Add(tbrSlider);
}

When this happens, you can reduce the number of ticks. This is done using
the TickFrequency property. Here is an example:
private void InitializeComponent()
{
tbrSlider = new TrackBar();
tbrSlider.Location = new Point(12, 12);
tbrSlider.Width = 400;
tbrSlider.SetRange(8, 255);
tbrSlider.Value = 125;

tbrSlider.TickFrequency = 10;

Controls.Add(tbrSlider);
}

This would produce:

The Tick Style

C# 3.0 Practical Learning II 601


The thumb’s visual display appears as a small standing pentagon with two
straight borders. Its appearance is set using the TickStyle property which is
based on the TickStyle enumeration. When you add a new TrackBar control
to a form, it is horizontally oriented, the thumb points down, the tick marks
are positioned under the sliding field. In this setting, the TickStyle property
is set to BottomRight. To place the tick marks above the sliding field, change
the value of the TickStyle property to TopLeft; this also has the effect of
reversing the direction of the slider. Here is an example:
private void InitializeComponent()
{
tbrSlider = new TrackBar();
tbrSlider.Location = new Point(12, 12);
tbrSlider.Width = 400;
tbrSlider.SetRange(8, 255);
tbrSlider.Value = 125;
tbrSlider.TickFrequency = 10;

tbrSlider.TickStyle = TickStyle.TopLeft;

Controls.Add(tbrSlider);
}

This would produce:

As a third option, you can have the tick marks on both sides of the slider. To
get this, set the TickStyle property to Both. With this value, the thumb
becomes a small rectangle (changing from its pentagon shape):

The Small Change


When the user presses one of the arrow keys, the thumb moves by one tick.
This unit is known as the SmallChange property. If you want the thumb to
move by more than one tick, you can assign the desired value to this
property. Alternatively, you can calculate a fraction of the difference between
the Minimum and the Maximum values then use it as the SmallChange.

The Large Change

C# 3.0 Practical Learning II 602


When the user presses either the Page Up (PgUp) or the Page Down (PgDn)
keys, the thumb moves by a value represented by the LargeChange property.
If the default value of this property is not convenient for your application,
you can change it to a new desired value or you can use a fraction of the
difference between the Minimum and the Maximum properties then use it as
the LargeChange.

Applications:
Car Inventory

Windows Controls: Check Boxes


 

Introduction
A check box is a control that makes a statement true or false. To perform this validation,
the control displays a small square box that the user can click. Here are examples:

C# 3.0 Practical Learning II 603


To start, the square box may be empty . If the user clicks it, a check mark appears in the
user clicks a check box that has a check mark in it, the check mark may be removed.

To let the user know what the check box control represents, the control is accompanied by a l
statement. When the square box is empty , the statement is false. When the square box
mark , the statement is true.

Creating a Check Box


To support check boxes, the .NET Framework provides the CheckBox class. To add a
application at design time, from the Common Controls section of the Toolbox, yon can click
and click the form or a container on the form. Unlike the radio button but like the regular comm
box can safely be positioned directly on a form.

To programmatically create a check box, declare a variable of type CheckBox, use the new
memory for it, and add it to the Controls collection of its holder. Here is an example:
using System;
using System.Drawing;
using System.Windows.Forms;

public class Exercise : System.Windows.Forms.Form


{
CheckBox chkValidate;

public Exercise()
{
InitializeComponent();
}

private void InitializeComponent()


{
chkValidate = new CheckBox();

Controls.Add(chkValidate);
}
}

public class Program


{
static int Main()
{
System.Windows.Forms.Application.Run(new Exercise());
return 0;
}
}

Unlike the radio button that usually comes along with other radio buttons, a check box can appear
comes in a group with others, the behavior of one check box is independent of the other check box
to the same group.

C# 3.0 Practical Learning II 604


Practical Learning: Introducing Check Boxes
1. Start a new Windows Application named DaniloPizza1

2. In the Solution Explorer, right-click Form1.cs and click Rename

3. Type Exercise.cs and press Enter

4. On the main menu, click Project -> Add New Item...

5. In the Templates list, click Icon File

6. Set the Name to pizza and click Add

7. Using the Erase tool , wipe its interior to erase its content

8. Use the Ellipse tool and the black color to draw an oval shape
 

9. Fill it up with a brown color (the color on the right side of the black)

10. Click the red color

11. Click the Airbrush tool

12. Click the option button and select the Medium brush
 

13. Randomly click different parts of the shape


 

C# 3.0 Practical Learning II 605


14. To give the appearance of a crust, use the Pencil tool , click the black color, righ
color, and draw a dark border around the shape

15. With still the black and the brown colors, randomly click and right-click different poi
 

16. Click the white color. Right-click the yellow color. Randomly click and right-click a fe

17. Click the brown color again and click the Line tool

18. Randomly draw horizontal, vertical, and dialog lines in the shape
 

19. Right-click a white section in the drawing area, position the mouse on Current Icon

C# 3.0 Practical Learning II 606


click 16x16, 16 Colors

20. Design it as follows:


 

21. Save the icon and close it

22. Use the Icon field of the form in the Properties window to assign the pizza.ico icon t

23. Design the form as follows:


 

Additional
Control Text Name
Properties

C# 3.0 Practical Learning II 607


GroupBox Pizza Size    

RadioButton Small rdoSmall  

TextBox 8.95 txtSmall AlignText: Right

RadioButton Medium rdoMedium Checked: True

TextBox 10.75 txtMedium AlignText: Right

RadioButton Large rdoLarge  

TextBox 12.95 txtLarge AlignText: Right

GroupBox Side Orders    

Label Qty    

Label Unit Price    

Label Sub Total    

Label Bread Sticks    

TextBox 0 txtQtyBread AlignText: Right

TextBox 3.25 txtPriceBread AlignText: Right

AlignText: Right
TextBox 0.00 txtTotalBread
ReadOnly: True

C# 3.0 Practical Learning II 608


Label Buffalo Wings    

TextBox 0 txtQtyWings AlignText: Right

TextBox 2.15 txtPriceWings AlignText: Right

AlignText: Right
TextBox 0.00 txtTotalWings
ReadOnly: True

GroupBox Toppings    

CheckBox Pepperoni chkPepperoni  

CheckBox Sausage chkSausage  

CheckBox Extra Cheese chkExtraCheese  

CheckBox Olives chkOlives  

CheckBox Onions chkOnions  

Label Each Topping    

TextBox 0.45 txtEachTopping AlignText: Right

GroupBox Drinks    

Label Qty    

Label Unit Price    

C# 3.0 Practical Learning II 609


Label Sub Total    

Label Soda Can    

TextBox 0 txtQtyCan AlignText: Right

TextBox 1.45 txtPriceCan AlignText: Right

AlignText: Right
TextBox 0.00 txtTotalCan
ReadOnly: True

Label Soda 20 Oz.    

TextBox 0 txtQtySoda20 AlignText: Right

TextBox 1.45 txtPriceSoda20 AlignText: Right

AlignText: Right
TextBox 0.00 txtTotalSoda20
ReadOnly: True

Label Soda 2L Bottle    

TextBox 0 txtQtySoda2L AlignText: Right

TextBox 1.45 txtPriceSoda2L AlignText: Right

AlignText: Right
TextBox 0.00 txtTotalSoda2L
ReadOnly: True

Label Orange Juice    

C# 3.0 Practical Learning II 610


TextBox 0 txtQtyOJ AlignText: Right

TextBox 2.25 txtPriceOJ AlignText: Right

AlignText: Right
TextBox 0.00 txtTotalOJ
ReadOnly: True

Label Water    

TextBox 0 txtQtyWater AlignText: Right

TextBox 1.25 txtPriceWater AlignText: Right

AlignText: Right
TextBox 0.00 txtTotalWater
ReadOnly: True

Button Close btnClose  

Label Total Price    

AlignRight: Right
TextBox 0.00 txtTotalPrice
ReadOnly: True

24. Save everything

Windows Controls: Check Boxes


Check Box Characteristics
 

C# 3.0 Practical Learning II 611


Checking a Check Box
By default, a check box appears empty, which makes its statement false. To make the
statement true, the user can click it. There are three main ways you can use this property
of a check box. To select a check box, you can set its Checked property to True. You can
also do it programmatically as follows:
private void Form1_Load(object sender,
System.EventArgs e)
{
checkBox1.Checked = true;
}

To find out if an item is selected, get the value of its Checked property. Another possibility co
state of the check mark. For example, you can check or uncheck the check mark when th
button. To do this, you can simply negate the truthfulness of the control as follows:
checkBox1.Checked = ! checkBox1.Checked;

Like the radio button, when a check box is clicked, the control fires a CheckedChanged event t
has been checked. This event is of type EventArgs. If the check box can display only two states,
this event is enough.

Practical Learning: Configuring Check Boxes


1. On the form click the Small radio button

2. Press and hold Shift

3. Click the Medium radio button, the Large radio button, the Pepperoni, the Sausage, the Ex
Olives, and the Onions check boxes

4. Release Shift

5. In the Properties window, click the Events button

6. In the Events section, double-click Click

7. Return to the form

8. Click the txtSmall text box

9. Press and hold Shift

10. Click each of the following controls: txtMedium, txtLarge, txtEachTopping, txtQtyBread, txt
txtQtyWings, txtPriceWince, txtQtyCan, txtPriceCan, txtQtySoda20, txtPriceSoda20, txtQtyS
txtPriceSoda2L, txtQtyOJ, txtPriceOJ, txtQtyWater, and txtPriceWater

11. Release Shift

C# 3.0 Practical Learning II 612


12. In the Events section of the Properties window, double-click Leave

13. In the Code Editor, define a method named CalculatePrice() and implement the events as follow
 
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace DaniloPizza1
{
public partial class Exercise : Form
{
public Exercise()
{
InitializeComponent();
}

internal void CalculatePrice()


{
double PriceSize = 0.00;
double PriceEachTopping = 0.00, BWings, Bread,
SodaCan, Soda20, Soda2L, OJ,
Water, PriceToppings, TotalOrder;
int Pepperoni, Sausage, ExtraCheese, Onions, Olives;

try
{
// Get the price of pizza depending on the selected
size
if (rdoSmall.Checked == true)
PriceSize = double.Parse(txtSmall.Text);
if (rdoMedium.Checked == true)
PriceSize = double.Parse(txtMedium.Text);
if (rdoLarge.Checked == true)
PriceSize = double.Parse(txtLarge.Text);
}
catch (FormatException)
{
MessageBox.Show("The value you typed for the price " +
"of a pizza is invalid" +
"\nPlease try again");
}

// Get the price of a topping if it was selected


if (chkPepperoni.Checked == true)
Pepperoni = 1;
else
Pepperoni = 0;

if (chkSausage.Checked == true)

C# 3.0 Practical Learning II 613


C# 3.0 Practical Learning II 614
C# 3.0 Practical Learning II 615
C# 3.0 Practical Learning II 616
C# 3.0 Practical Learning II 617
C# 3.0 Practical Learning II 618
C# 3.0 Practical Learning II 619
button. You would have to find it out yourself, which is easily done by getting the value of the

The Appearance of a Check Box


By default, a check box appears as a square box that gets a check mark when the user clicks i
make a check box appear as a toggle button. In that case, the button would appear as a regu
user clicks it, it appears down. If the user clicks it again, it becomes up.

To change the appearance of a check box, assign the Button or Normal value to its Appea
Appearance values are defined in the Appearance enumeration. You can also do this program

private void Form1_Load(object sender, System.EventArgs e)


{
checkBox1.Checked = true;
checkBox1.ThreeState = true;
checkBox1.Appearance = Appearance.Button;
}

Like the radio button, the check box control fires an AppearanceChanged event when the
changes from Normal to Button or vice-versa.

Applications
Boolean Algebra

Windows Control: The Data Grid View


 

Data Grid View Fundamentals


 

Introduction
Like a list view, a data grid view is a rectangular control made of columns and rows:

C# 3.0 Practical Learning II 620


The top section of the control displays column headers as gray boxes with each showing
a caption. On the left side, there are gray boxes referred to as row headers. The cells are
the intersections of the columns and the rows. Those cells are white. These are the
default characteristics of columns, rows, and cells. In reality, most aspects can be
customized. They can show different colors, different widths, and different heights.

To use the data grid view, the user can identify a column, click a cell under it, and start
typing. By default, each cell behaves like a text box. The user can:

 Click into it to create a new entry

 Edit the content of a cell

 Right-click a cell to display the default context-sensitive menu of a text box as


defined in the Microsoft Windows operating system

As mentioned already, by default, the cells of a data grid view are made of
text boxes. If you want, you can make the cells under the columns into
combo boxes, check boxes, buttons, links, or pictures:

Remember that many aspects of  a data grid view can be customized. For
example, you can let the user change the width of a column. You can display a
context menu when the user right-clicks a column header or a row header. You

C# 3.0 Practical Learning II 621


can display a context menu when the user right-clicks any cell of the data grid
view.

Creating a Data Grid View


To support the data grid view, the Toolbox of Microsoft Visual Studio is

equipped with the DataGridView button . Therefore, to get a data grid


view, in the Data section of the Toolbox, you can click the DataGridView

button and click the form of your application. This would create a black
rectangular box on the form:

To support the data grid view, the .NET Framework provides a class named
DataGridView. Therefore, to programmatically create a data grid view,
declare a variable of type DataGridView and add it to the Controls collection
of the form. Here is an example:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace DataGridViewExercise1
{
public partial class Exercise : Form
{
DataGridView dgvStudents;

public Exercise()
{
InitializeComponent();
}

private void Exercise_Load(object sender, EventArgs e)


{
dgvStudents = new DataGridView();

C# 3.0 Practical Learning II 622


Controls.Add(dgvStudents);
}
}
}

As a normal Windows control, when creating it, make sure you specify some
of the regular characteristics such as the location, the size, the anchoring, the
docking, etc. Here is an example
using System;
using System.Drawing;
using System.Collections;
using System.Windows.Forms;

public class Exercise : Form


{
DataGridView dgvStudents;

public Exercise()
{
InitializeComponent();
}

void InitializeComponent()
{
Text = "Students Records";

dgvStudents = new DataGridView();


dgvStudents.Location = new Point(12, 12);
Controls.Add(dgvStudents);
}
}

public class Program


{
static int Main()
{
System.Windows.Forms.Application.Run(new Exercise());
return 0;
}
}

This would produce:

C# 3.0 Practical Learning II 623


The Columns of a Data Grid View
 

Introduction
As its name suggests, a data grid view is presented as a grid, which appears
like a spreadsheet made of columns. The columns organize a data grid view
in categories of information. To hold the columns of a data grid view, the
DataGridView class is equipped with a property named Columns. The
DataGridView.Columns property is of type
DataGridViewColumnCollection defined as follows:

[ListBindableAttribute(false)]
public class DataGridViewColumnCollection : BaseCollection,
IList,
ICollection,
IEnumerable

As you can see, this class implements the IList, the ICollection, and the
IEnumerable interfaces. This means that you can use the
DataGridViewColumnCollection class to create and manage columns.

Creating a Column
One of the first actions you should perform on a data grid view consists of
creating one or more columns. If you are visually creating a data grid view,
on the form, click the data grid view control. In the Properties window, click
Columns and click its ellipsis button. As an alternative, on the form, click the
data grid view and click the button on its top right section:

C# 3.0 Practical Learning II 624


Then click the Edit Columns button. In both cases, the Edit Columns dialog
box would come up:

To create a column, click the Add button. If you had clicked the button on the
top-right section of the data grid view, you can click the Add Column button.
In both cases, the Add Column dialog box would come up:

C# 3.0 Practical Learning II 625


The column of a data grid view is an object of type DataGridViewColumn.
Therefore, to programmatically create a column, you can declare a variable of
type DataGridViewColumn. and initialize it with its default constructor. Here
is an example:
private void Exercise_Load(object sender, EventArgs e)
{
dgvStudents = new DataGridView();
dgvStudents.Location = new Point(10, 10);
dgvStudents.Size = new Size(250, 100);

DataGridViewColumn colFirstName = new DataGridViewColumn();

Controls.Add(dgvStudents);
}

After a new column has been added, the data grid view fires a ColumnAdded
event, which is handled by the DataGridViewColumnEventArgs class.

Deleting a Column
If you do not want a certain column in your data grid view, you can remove
it. If you are visually working on the data grid view, open the Edit Columns
dialog box. To delete a column, click it in the Selected Columns list and click
the Remove button.

To assist you with programmatically deleting a column, the


DataGridViewColumnCollection class is equipped with a method named
Remove and that is overloaded with two versions. To delete a column based
on its name, you can use the following syntax:

C# 3.0 Practical Learning II 626


public virtual void Remove(string columnName);

To delete a column using its reference, the


DataGridViewColumnCollection class provides the following version:

public virtual void Remove(DataGridViewColumn


dataGridViewColumn);

When a column has been deleted, the data grid view fires a ColumnRemoved
event. This event also is handled by the DataGridViewColumnEventArgs class.

The Cell Template of a Column


In our introduction, we stated that the cells under a column could be made of
text boxes, combo boxes, buttons, pictures, or linked labels. When creating a
column, you must specify the type of control that the cells of a column would
be made of. If you are visually creating a column, in the Add Column combo
box, after specifying the name, click the arrow of the Type combo box and
select. To change the type of a column, open the Edit Columns dialog box
and click the column in the Selected Columns list. In the Properties section,
click the arrow of the ColumnType field and select the desired one:

The data grid view considers the column type as a cell template. To support
cell templates, the .NET Framework provides the DataGridViewCell class.
Except for the check box, you can use the DataGridViewCell class to
specify the type of cells a column should display. To do this, declare a
variable of type DataGridViewCell and use the new operator to initialize it with
one of the following classes:

 DataGridViewTextBoxCell: Used to display text boxes. Here is an


example:

C# 3.0 Practical Learning II 627


DataGridViewCell celFullName = new
DataGridViewTextBoxCell();

 DataGridViewComboBoxCell: Used to display combo boxes. Here is an


example:
DataGridViewCell celGender = new
DataGridViewComboBoxCell();

 DataGridViewButtonCell: Used to display buttons. Here is an


example:
DataGridViewCell celShowResume = new
DataGridViewButtonCell();

 DataGridViewImageCell: Used to display pictures. Here is an example:


DataGridViewCell celShowPicture = new
DataGridViewImageCell();

 DataGridViewLinkCell: Used to display linked labels. Here is an


example:
DataGridViewCell celEmailAddress = new
DataGridViewLinkCell();

After declaring and initializing the variable, you can assign it to the
CellTemplate property of the column. Here is an example:

private void Exercise_Load(object sender, EventArgs e)


{
dgvStudents = new DataGridView();
dgvStudents.Location = new Point(10, 10);
dgvStudents.Size = new Size(550, 100);

DataGridViewColumn colFullName = new DataGridViewColumn();


DataGridViewCell celFullName = new
DataGridViewTextBoxCell();
colFullName.CellTemplate = celFullName;

Controls.Add(dgvStudents);
}

Once the new column has been built, to make it possible to actually add it to
the data grid, the DataGridViewColumnCollection class is equipped with a
method named Add that comes in two versions. One of its flavors uses the
following syntax:
public virtual int Add(DataGridViewColumn dataGridViewColumn)

This version takes a DataGridViewColumn object as argument. If it succeeds


in adding the new column, the method returns its index. Here are examples
of calling this method:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;

C# 3.0 Practical Learning II 628


using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace Exercise3
{
public partial class Exercise : Form
{
DataGridView dgvStudents;

public Exercise()
{
InitializeComponent();
}

private void Exercise_Load(object sender, EventArgs e)


{
dgvStudents = new DataGridView();
dgvStudents.Location = new Point(10, 10);
dgvStudents.Size = new Size(550, 100);

DataGridViewColumn colFullName = new


DataGridViewColumn();
DataGridViewCell celFullName = new
DataGridViewTextBoxCell();
colFullName.CellTemplate = celFullName;
dgvStudents.Columns.Add(colFullName);

DataGridViewColumn colGender = new


DataGridViewColumn();
DataGridViewCell celGender = new
DataGridViewComboBoxCell();
colGender.CellTemplate = celGender;
dgvStudents.Columns.Add(colGender);

DataGridViewColumn colShowResume = new


DataGridViewColumn();
DataGridViewCell celShowResume = new
DataGridViewButtonCell();
colShowResume.CellTemplate = celShowResume;
dgvStudents.Columns.Add(colShowResume);

DataGridViewColumn colShowPicture = new


DataGridViewColumn();
DataGridViewCell celShowPicture = new
DataGridViewImageCell();
colShowPicture.CellTemplate = celShowPicture;
dgvStudents.Columns.Add(colShowPicture);

DataGridViewColumn colEmailAddress = new


DataGridViewColumn();
DataGridViewCell celEmailAddress = new
DataGridViewLinkCell();
colEmailAddress.CellTemplate = celEmailAddress;
dgvStudents.Columns.Add(colEmailAddress);

C# 3.0 Practical Learning II 629


Controls.Add(dgvStudents);
}
}
}

This would produce:

As an alternative to specifying the types of cells of a column, the .NET


Framework provides a class for each type of column:

 DataGridViewTextBoxColumn: This is used to let the cells display as


text boxes

 DataGridViewComboBoxColumn: This is used to let the cells display as


combo boxes

 DataGridViewCheckBoxColumn: This is used to let the cells display as


check boxes

 DataGridViewButtonColumn: This is used to let the cells display as


buttons

 DataGridViewImageColumn: This is used to let the cells display as


pictures

 DataGridViewLinkColumn: This is used to let the cells display as linked


labels

Each one of these classes inherits from the DataGridViewColumn. This


means they share many characteristics they get from their common parent.

To specify the types of cells of a column, declare a variable using one of


these classes and initialize it using its default constructor, then pass it to the
Add() method of the Columns property of the data grid view. Here are
examples:
private void Exercise_Load(object sender, EventArgs e)
{
dgvStudents = new DataGridView();
dgvStudents.Location = new Point(10, 10);
dgvStudents.Size = new Size(645, 100);

DataGridViewTextBoxColumn colFullName = new


DataGridViewTextBoxColumn();

C# 3.0 Practical Learning II 630


dgvStudents.Columns.Add(colFullName);

DataGridViewComboBoxColumn colGender = new


DataGridViewComboBoxColumn();
dgvStudents.Columns.Add(colGender);

DataGridViewCheckBoxColumn colShowResume = new


DataGridViewCheckBoxColumn();
dgvStudents.Columns.Add(colShowResume);

DataGridViewButtonColumn colShowPicture = new


DataGridViewButtonColumn();
dgvStudents.Columns.Add(colShowPicture);

DataGridViewLinkColumn colEmailAddress = new


DataGridViewLinkColumn();
dgvStudents.Columns.Add(colEmailAddress);

DataGridViewImageColumn colPicture = new


DataGridViewImageColumn();
dgvStudents.Columns.Add(colPicture);

Controls.Add(dgvStudents);
}

This would produce:

If you create the column to show combo box, to create the values of the
combo box, the DataGridViewComboBoxColumn class is equipped with a
property named Items. This property is of type ObjectCollection and is
created inside the DataGridViewComboBoxCell class. Here is an example of
calling the Add() method of this class:
private void Exercise_Load(object sender, EventArgs e)
{
dgvStudents = new DataGridView();
dgvStudents.Location = new Point(10, 10);
dgvStudents.Size = new Size(420, 80);

DataGridViewTextBoxColumn colFirstName = new


DataGridViewTextBoxColumn();
dgvStudents.Columns.Add(colFirstName);

DataGridViewTextBoxColumn colLastName = new


DataGridViewTextBoxColumn();

C# 3.0 Practical Learning II 631


dgvStudents.Columns.Add(colLastName);

DataGridViewComboBoxColumn colGender = new


DataGridViewComboBoxColumn();

colGender.Items.Add("Male");
colGender.Items.Add("Female");
colGender.Items.Add("Unknown");

dgvStudents.Columns.Add(colGender);
}

The Name of a Column


Because a column is an object in its own right, it has a name (an object
name). If you visually create a column, a default name would be given to it in
the Name text box of the Add Column dialog. You can accept that name or
change it. After creating a column, to change its name, open the Edit
Columns dialog box and click the column in the Selected Columns list. In the
Properties section, click the (Name) field and change its value.

To programmatically specify the name of a column, you have various options.


If you use the DataGridViewColumn class to create a column, it is equipped
with a property named Name. Therefore, to specify the name of the column,
assign a string to that property. The name of a column can be anything. Here
is an example:
private void Exercise_Load(object sender, EventArgs e)
{
dgvStudents = new DataGridView();
dgvStudents.Location = new Point(10, 10);
dgvStudents.Size = new Size(550, 100);

DataGridViewColumn colFullName = new


DataGridViewColumn();
colFullName.Name = "2 Four 1 @ U$";
DataGridViewCell celFullName = new
DataGridViewTextBoxCell();
colFullName.CellTemplate = celFullName;
dgvStudents.Columns.Add(colFullName);

Controls.Add(dgvStudents);
}

To make it simple and practical, we will use C# rules to name our columns.

If you use one of the DataGridViewControlColumn classes, we saw that they


derive from the DataGridViewColumn class. Therefore, after instantiating a
column using one of those classes, to specify its name, assign a string to its
Name property.

The Caption of a Column

C# 3.0 Practical Learning II 632


When a data grid view displays its columns, the user should be able to
identify each. To make it possible, each column should display a string in the
column header, the top box of a column. That string is called the caption (or
text, or header text) of the column.

If you are visually creating a column, a default caption is given in the Header
Text box. You can accept that string or change it. After creating a column, to
change its caption, open the Edit Columns dialog box and click the column in
the Selected Columns list. In the Properties section, click the HeaderText field
and change its value.

To programmatically specify or change the caption of a column, you have


various options. If you specify the name of a column, the compiler would
apply it as the caption of the column. Here is an example:
private void Exercise_Load(object sender, EventArgs e)
{
dgvStudents = new DataGridView();
dgvStudents.Location = new Point(10, 10);
dgvStudents.Size = new Size(150, 100);

DataGridViewColumn colFullName = new DataGridViewColumn();


colFullName.Name = "FullName"
DataGridViewCell celFullName = new
DataGridViewTextBoxCell();
colFullName.CellTemplate = celFullName;
dgvStudents.Columns.Add(colFullName);

Controls.Add(dgvStudents);
}

This would produce:

Otherwise, to support the caption of a column, the DataGridViewColumn


class is equipped with a property named HeaderText. Therefore, to specify
the caption of a column, assign a string to this property. Here is an example:
private void Exercise_Load(object sender, EventArgs e)
{
dgvStudents = new DataGridView();
dgvStudents.Location = new Point(10, 10);
dgvStudents.Size = new Size(150, 100);

DataGridViewColumn colFullName = new DataGridViewColumn();

C# 3.0 Practical Learning II 633


colFullName.Name = "FullName";
colFullName.HeaderText = "Full Name";

DataGridViewCell celFullName = new


DataGridViewTextBoxCell();
colFullName.CellTemplate = celFullName;
dgvStudents.Columns.Add(colFullName);

Controls.Add(dgvStudents);
}

This would produce:

In the same way, if you use one of the DataGridViewControlColumn classes


to create a column, you can assign a string to its HeaderText property to
specify its caption.

So far, to programmatically create a column, we were using either the


DataGridViewColumn or one of its derived DataGridViewControlColumn
classes. After creating the column, we were calling a version of the
DataGridViewColumnCollection.Add() method to add the new column.
To make it a little simpler to create a column, the
DataGridViewColumnCollection class is equipped with a second version of
the Add() method. Its syntax is:
public virtual int Add(string columnName, string headerText);

This version allows you to create a column by specifying its object name and
its caption. Here are examples:
private void Exercise_Load(object sender, EventArgs e)
{
dgvStudents = new DataGridView();
dgvStudents.Location = new Point(10, 10);
dgvStudents.Size = new Size(350, 100);

dgvStudents.Columns.Add("FirsName", "First Name");


dgvStudents.Columns.Add("LasName", "Last Name");
dgvStudents.Columns.Add("Gender", "Gender");

Controls.Add(dgvStudents);
}

This would produce:

C# 3.0 Practical Learning II 634


As you can see, the default type of a column created using the
DataGridViewColumnCollection.Add(Name, Caption) method is a text box. If
you want a different type of column, you should use one of the techniques we
saw earlier to create the column.

The Width of a Column


The width of a column is the distance from its left to its right borders. When
you create a column (whether visually or programmatically), it receives a
default width. For you to visually change the width of a column, in the Edit
Columns dialog box, click the column in the Selected Columns list box. Then,
in the Properties section, click the Width field and change its value.

To assist you with programmatically specifying the width of a column, the


DataGridViewColumn class is equipped with an integral property named
Width. Therefore, to specify or change the width of a column, assign an
integer to this property.

By default, when a data grid view displays its columns, the user is able to
resize any of them. To do this, the user can position the mouse on the
separating line of two columns, click, and drag left or right. If you want, you
can allow this or prevent the user from resizing a column. This characteristic
is controlled by the Resizable Boolean property of the DataGridColumn
class. The default value of the DataGridColumn.Resizable property is true,
which indicates that the user can resize it. To prevent this change, you can
set this property to false:

C# 3.0 Practical Learning II 635


Of course, you can also control this characteristic by assigning a true or false
value to the property.

There are various ways the user can resize a column. The user can position
the mouse on the right border of a column header, click and hold down the
mouse, then drag left or right. The user can also double-click the right border
of a column. However the user does this, when the width of a column has
been changed, the data grid view fires a ColumnWidthChanged event. This
event is handled by the DataGridViewColumnEventArgs class. If the user
double-clicks the right border of a column, the control fires a
ColumnDividerDoubleClick event. This event is handled by the
DataGridViewColumnDividerDoubleClickEventArgs class.

Referring to a Column
In some operations, you will need to indicate the column you want to access.
If you are working visually, open the Edit Columns dialog box and click the
column in the Selected Columns list.

To programmatically refer to a column, you have various options. The


DataGridViewColumnCollection class is equipped with an indexed property
(named Item) that allows you to refer to a column either by its index or by its
object name. Here is an example:
private void Exercise_Load(object sender, EventArgs e)
{
dgvStudents = new DataGridView();
dgvStudents.Location = new Point(10, 10);
dgvStudents.Size = new Size(350, 100);

dgvStudents.Columns.Add("FirsName", "First Name");

C# 3.0 Practical Learning II 636


dgvStudents.Columns.Add("LasName", "Last Name");
dgvStudents.Columns.Add("Gender", "Gender");

MessageBox.Show(dgvStudents.Columns[1].HeaderText);

Controls.Add(dgvStudents);
}

The Records of a Data Grid View


 

Introduction to Rows
After creating a data grid view and its columns, you can start populating it
with values. When the data grid view comes up, the user can click a cell.
When the user clicks a cell, that cell becomes highlighted, indicating that it
has received focus. Here is an example:

When a cell receives focus, the data grid view fires a CellEnter Event. This
event is handled by the DataGridViewCellEventArgs class. This class is
equipped with two properties named ColumnIndex and RowIndex. The
ColumnIndex property indicates the index of the column that was clicked.
The RowIndex property indicates the index of the column that was clicked.

After clicking a cell, the user can start typing if the cell is text-based. If the
cell already contained a value, the user can click it first to give it focus and
then edit its content. When the user starts editing the value of a cell, the data
grid view fires a CellBeginEdit event, which is handled by the
DataGridViewCellCancelEventArgs class. As its name suggests, the
primary characteristic of this class is that it allows you to accept or reject
what the user is doing. After the user has edited the value of  a cell, the data
grid view fires a CellEndEdit event. This event is handled by the
DataGridViewCellEventArgs class. When this ends, the cell should have a
new value. Here is an example:

C# 3.0 Practical Learning II 637


If the cell is not text-based, the user can select the check box or use the
content, based on its type. Either way, when the value of a cell has changed,
the data grid view fires a CellValueChanged event, which is handled by the
DataGridViewCellEventArgs class.

After specifying the value of a cell or taking the necessary action, the user
can move to another cell. When a cell loses focus, the data grid view fires a
CellLeave event. This event is handled by the
DataGridViewCellEventArgs class.

The user can perform these operations for each cell under the columns. The
row of cells at the same level under the columns is called a record. Here is an
example of a record with the values Joyce, Simms, and Female:

Each row starts with a gray box on the left side. When the user clicks a cell of
a particular row, the data grid view fires a RowEnter event that indicates that
the row has just received focus. Then, the gray box of that record becomes
equipped with a pen icon. The RowEnter event is handled by the
DataGridViewCellEventArgs class. If the user clicks a cell of another row,
such as a cell above it, under it, or a column header, the data grid view fires
a RowLeave event, which indicates that the previous row lost focus. The
RowLeave event also is handled by the DataGridViewCellEventArgs class.

A record that has been added already displays an empty gray box. The next
empty record has a gray box with a *. The line between two rows is called a row
divider.

The Rows of a Data Grid View


To support the records of a data grid view, the DataGridView class is
equipped with a property named Rows, which is a collection. The

C# 3.0 Practical Learning II 638


DataGridView.Rows property is an object of type
DataGridViewRowCollection:

[ListBindableAttribute(false)]
public class DataGridViewRowCollection : IList,
ICollection,
IEnumerable

As you can see, this class implements the IList, the ICollection, and the
IEnumerable interfaces. Since a data grid view can have many records, the
records are stored in a zero-based indexed collection. The first record has an
index of 0. The second has an index of 1, and so on. To support this, the
DataGridViewRowCollection class is equipped with an indexed property
(named Item) that is overloaded with two versions. Therefore, to refer to a
record, apply the [] operator to the DataGridView.Rows property. An
example would be:
private void Exercise_Load(object sender, EventArgs e)
{
dgvStudents = new DataGridView();
dgvStudents.Location = new Point(10, 10);
dgvStudents.Size = new Size(350, 100);

dgvStudents.Columns.Add("FirsName", "First Name");


dgvStudents.Columns.Add("LasName", "Last Name");
dgvStudents.Columns.Add("Gender", "Gender");

Controls.Add(dgvStudents);

dgvStudents.Rows[0] . . .
}

In the same way, if a data grid view contains many records, you can refer to
any, based on its index. The index refers to the gray box on the left of the
record.

Each member of the DataGridViewRowCollection collection is an object of


type DataGridViewRow:
public class DataGridViewRow : DataGridViewBand

This allows you to get a reference to a row and do what is needed.

There are various things the user can do with a row header. For example, the
user can click a row header. A row header that has been clicked becomes
equipped with a right-pointing arrow and its cells become selected:

C# 3.0 Practical Learning II 639


When the user clicks a row header, the data grid view fires a
RowHeaderMouseClick event. This event is handled by the
DataGridViewCellMouseEventArgs class. This class is equipped with two
properties named ColumnIndex and RowIndex. The ColumnIndex property
indicates the index of the column that was clicked. The RowIndex property
indicates the index of the column that was clicked.

The user can also double-click a row header and you can take action if
necessary. When the user double-clicks a row header, the data grid view fires
a RowHeaderMouseDoubleClick event. This event is handled by the
DataGridViewCellMouseEventArgs class.

The Height of a Row


When a new record is created, its row receives a default height, which is the
distance from its top to its bottom borders. The user can accept or change
the height of a row. To do this, the user can click and drag the bottom border
of a row header. If the values in a row are too tall for a height, the bottom
parts of those values may not appear. In other cases, the height of a row
might be too high for the values of a row. To let the data grid view adjust the
height of a row to be just as necessary, the user can double-click the bottom
border of the row.

If the user double-click the bottom border of a row, the data grid view fires a
RowDividerDoubleClick event. This event is handled by the
DataGridViewRowDividerDoubleClickEventArgs class. The
DataGridViewRowDividerDoubleClickEventArgs class is equipped with one
property named RowIndex, which holds the index of the row whose bottom
border was double-clicked.

The Cells of a Data Grid View


 

Introduction
A data grid view is meant to display values and these values are stored in
cells. Under each column header is a box called a cell. To add a value to a

C# 3.0 Practical Learning II 640


data grid view, you (actually the user) click one of those cells. When a cell
has been clicked, the data grid view fires a CellClick event. This event is
handled by the DataGridViewCellEventArgs class. The user can also
double-click a cell. In this case, the data grid view fires a CellDoubleClick
event. This event is handled by the DataGridViewCellEventArgs class.

If the user clicks the content (it could be its value) of a cell, the data grid
view fires a CellContentClick event. This event is handled by the
DataGridViewCellEventArgs class.

After clicking a cell, the user can start typing the desired value. The user can
also double-click the content of a cell. In this case, the data grid view fires a
CellContentDoubleClick event. This event is handled by the
DataGridViewCellEventArgs class.

The Cells of a Row


As stated already, either you or the user can create values for cells. The user
can add one value at a time. You too can either create each value or add
them in a group. The user must identify a cell, click it and then start typing.
You too, at any time, should know what cell is receiving, or needs, attention.
To assist you with identifying a cell, the DataGridViewRow class is equipped
with a property named Cells. This property itself is a collection created from
a class named DataGridViewCellCollection:
ListBindableAttribute(false)]
public class DataGridViewCellCollection : BaseCollection,
IList,
ICollection,
IEnumerable

This is a typical collection class that implements the IList, the ICollection,
and the IEnumerable interfaces. This class allows you to refer to a record,
which is primarily a collection of cells that share the same row. To support
this idea of a range of cells, the DataGridViewCellCollection class is
equipped with an indexed property (named Item) that is overloaded with two
versions. One of the versions allows you to refer to a cell based on the index
of its column. The most left cell of a row has an index of 0. The second from
left has an index of 1, and so on. 

To identify a cell in a record, you use the concept of a cell being the
intersection of a row and a column. Therefore, you can use the
DataGridView.Rows[] indexed property to specify the record. Then access
the DataGridViewRow.Cells[] indexed property to specify the column
under which the cell exists. Here is an example:
private void Exercise_Load(object sender, EventArgs e)
{
dgvStudents = new DataGridView();

C# 3.0 Practical Learning II 641


dgvStudents.Location = new Point(10, 10);
dgvStudents.Size = new Size(350, 100);

dgvStudents.Columns.Add("FirsName", "First Name");


dgvStudents.Columns.Add("LasName", "Last Name");
dgvStudents.Columns.Add("Gender", "Gender");

Controls.Add(dgvStudents);

// First Record
dgvStudents.Rows[0] . . .
// Second Record
dgvStudents.Rows[1] . . .
// Intersection of: First Record - First Column
dgvStudents.Rows[0].Cells[0] . . .
// Intersection of: First Record - Second Column
dgvStudents.Rows[0].Cells[1] . . .
// Intersection of: Second Record - First Column
dgvStudents.Rows[1].Cells[0] . . .
// Intersection of: Second Record - Second Column
dgvStudents.Rows[1].Cells[1] . . .
}

Using the index of a column supposes that you know the exact sequence of
columns. As an alternative, you can be more precise by using the object
name of a column. To support this, the DataGridViewRow.Cells[] indexed
property has another version that takes a string as argument. Here is an
example:
private void Exercise_Load(object sender, EventArgs e)
{
dgvStudents = new DataGridView();
dgvStudents.Location = new Point(10, 10);
dgvStudents.Size = new Size(350, 100);

dgvStudents.Columns.Add("FirsName", "First Name");


dgvStudents.Columns.Add("LasName", "Last Name");
dgvStudents.Columns.Add("Gender", "Gender");

Controls.Add(dgvStudents);

dgvStudents.Rows[0].Cells[0]
dgvStudents.Rows[0].Cells[1]

dgvStudents.Rows[0].Cells["Gender"] . . .
}

Once you have identified a cell, you can then do in it what you want. 

The Value of a Cell


Probably the most important aspect of a cell is its content. The default
content of a cell is its text. This is typical of a text-based cell. We have
already seen how to identify a cell. To identify its value, the

C# 3.0 Practical Learning II 642


DataGridViewCell class is equipped with a property named Value.
Therefore, to add a value to a cell, assign the desired string to its Value
property. Here are examples:
private void Exercise_Load(object sender, EventArgs e)
{
dgvStudents = new DataGridView();
dgvStudents.Location = new Point(10, 10);
dgvStudents.Size = new Size(350, 100);

dgvStudents.Columns.Add("FirsName", "First Name");


dgvStudents.Columns.Add("LasName", "Last Name");
dgvStudents.Columns.Add("Gender", "Gender");

Controls.Add(dgvStudents);

dgvStudents.Rows[0].Cells[0].Value = "Joyce";
dgvStudents.Rows[0].Cells[1].Value = "Simms";
dgvStudents.Rows[0].Cells["Gender"].Value =
"Female";
}

This would produce:

If a cell is a check box, to specify its value, assign true or false to its Value
property. Here is an example:
private void Exercise_Load(object sender, EventArgs e)
{
dgvStudents = new DataGridView();
dgvStudents.Location = new Point(10, 10);
dgvStudents.Size = new Size(320, 80);

DataGridViewTextBoxColumn colFirstName = new


DataGridViewTextBoxColumn();
colFirstName.Name = "FirstName";
colFirstName.HeaderText = "First Name";
dgvStudents.Columns.Add(colFirstName);

DataGridViewTextBoxColumn colLastName = new


DataGridViewTextBoxColumn();
colLastName.Name = "LastName";
colLastName.HeaderText = "Last Name";
dgvStudents.Columns.Add(colLastName);

C# 3.0 Practical Learning II 643


DataGridViewCheckBoxColumn colFullTime = new
DataGridViewCheckBoxColumn();
colFullTime.Name = "FullTime";
colFullTime.HeaderText = "Full Time?";
colFullTime.Width = 70;
dgvStudents.Columns.Add(colFullTime);

Controls.Add(dgvStudents);

dgvStudents.Rows[0].Cells[0].Value = "Ernestine";
dgvStudents.Rows[0].Cells[1].Value = "Cavier";
dgvStudents.Rows[0].Cells[2].Value = true;
}

This would produce:

If the column is a combo box, you can assign a string to its Value property.
The value should be one of the items in the combo box.

If the column is configured for web links, you can assign a string to its Value
property. You should make sure the string is either a valid URL or an email
address. Here is an example:
private void Exercise_Load(object sender, EventArgs e)
{
dgvStudents = new DataGridView();
dgvStudents.Location = new Point(10, 10);
dgvStudents.Size = new Size(540, 80);

DataGridViewTextBoxColumn colFirstName = new


DataGridViewTextBoxColumn();
colFirstName.Name = "FirstName";
colFirstName.HeaderText = "First Name";
dgvStudents.Columns.Add(colFirstName);

DataGridViewTextBoxColumn colLastName = new


DataGridViewTextBoxColumn();
colLastName.Name = "LastName";
colLastName.HeaderText = "Last Name";
dgvStudents.Columns.Add(colLastName);

DataGridViewComboBoxColumn colGender = new


DataGridViewComboBoxColumn();
colGender.Name = "Gender";
colGender.Items.Add("Male");
colGender.Items.Add("Female");
colGender.Items.Add("Unknown");

C# 3.0 Practical Learning II 644


dgvStudents.Columns.Add(colGender);

DataGridViewCheckBoxColumn colFullTime = new


DataGridViewCheckBoxColumn();
colFullTime.Name = "FullTime";
colFullTime.HeaderText = "Full Time?";
colFullTime.Width = 70;
dgvStudents.Columns.Add(colFullTime);

DataGridViewLinkColumn colEmailAddress = new


DataGridViewLinkColumn();
colEmailAddress.HeaderText = "Email Address";
colEmailAddress.Width = 120;
dgvStudents.Columns.Add(colEmailAddress);

Controls.Add(dgvStudents);

dgvStudents.Rows[0].Cells[0].Value = "Ernestine";
dgvStudents.Rows[0].Cells[1].Value = "Cavier";
dgvStudents.Rows[0].Cells[2].Value = "Female";
dgvStudents.Rows[0].Cells[3].Value = true;
dgvStudents.Rows[0].Cells[4].Value =
"caviere@emailfrance.fr";
}

This would produce:

Creating a Record
We mentioned that, when a user adds a new value into a cell, a new empty
record is created under that row. Also, by default, after you have just created
the columns of a data grid view, the studio adds an empty record to it. If you
work programmatically, you do not get the same feature, or only one default
empty record is given to you. Therefore, before creating one or more values
for a record, you must make sure there is an empty record ready to receive
your values. This means that you must first create a (an empty) record. You
have various options.

To assist you with creating new records, the DataGridViewRowCollection


class is equipped with a method named Add and that is overloaded with 4
versions. One of the versions uses the following syntax:
public virtual int Add()

C# 3.0 Practical Learning II 645


This version of the DataGridViewRowCollection.Add() method allows you
to create one empty record. Here is an example of calling it:
private void Exercise_Load(object sender, EventArgs e)
{
dgvStudents = new DataGridView();
dgvStudents.Location = new Point(10, 10);
dgvStudents.Size = new Size(350, 100);

dgvStudents.Columns.Add("FirstName", "First Name");


dgvStudents.Columns.Add("LastName", "Last Name");
dgvStudents.Columns.Add("Gender", "Gender");

Controls.Add(dgvStudents);

dgvStudents.Rows.Add();
}

You may want to create many records before adding values to them. To
support this, the DataGridViewRowCollection class provides another
version of the Add() method. Its syntax is:
public virtual int Add(int count);

When calling this method, pass the desired number of records as argument.
Once you have created the records, you can then add the desired values.
Here is an example of calling Add():
private void Exercise_Load(object sender, EventArgs e)
{
dgvStudents = new DataGridView();
dgvStudents.Location = new Point(10, 10);
dgvStudents.Size = new Size(350, 200);

dgvStudents.Columns.Add("FirstName", "First Name");


dgvStudents.Columns.Add("LastName", "Last Name");
dgvStudents.Columns.Add("Gender", "Gender");

Controls.Add(dgvStudents);

dgvStudents.Rows.Add(4);

dgvStudents.Rows[0].Cells[0].Value = "Joyce";
dgvStudents.Rows[0].Cells[1].Value = "Simms";
dgvStudents.Rows[0].Cells["Gender"].Value =
"Female";

dgvStudents.Rows[1].Cells["FirstName"].Value =
"Peter";
dgvStudents.Rows[1].Cells[1].Value = "Mukoko";
dgvStudents.Rows[1].Cells[2].Value = "Male";
}

Instead of adding the values of cells one at a time, you can store them in an
array, then add the whole when it is ready. To support this, the

C# 3.0 Practical Learning II 646


DataGridViewRowCollection class is equipped with the following version of
the Add() method:
public virtual int Add(object[] values);

 This version expects an array of objects as arguments. Here is an example:


private void Exercise_Load(object sender, EventArgs e)
{
dgvStudents = new DataGridView();
dgvStudents.Location = new Point(10, 10);
dgvStudents.Size = new Size(350, 200);

dgvStudents.Columns.Add("FirstName", "First Name");


dgvStudents.Columns.Add("LastName", "Last Name");
dgvStudents.Columns.Add("Gender", "Gender");

Controls.Add(dgvStudents);

string[] AHRecord = { "Adrian", "Hewitt", "Male" };


dgvStudents.Rows.Add(AHRecord);
}

Windows Control: The Group Box


 

Description
A group is a window that draws a bordered line all around. This makes it
draw a limiting placeholder for other controls. To indicate what it is used for,
a group box may display a title, also referred to as its caption. Here is an
example of a group box on a form:

Group Box Creation

C# 3.0 Practical Learning II 647


To support group box, the .NET Framework provides the GroupBox class. At
design time, to add a group box to your application, from the Containers
section of the Toolbox, click GroupBox and click the form (or another
container). To programmatically create a group box, you can create a handle
to GroupBox, allocate memory for it using the new operator, and add it to the
Controls collection of its container. Here is an example:
using System;
using System.Drawing;
using System.Windows.Forms;

public class Exercise : System.Windows.Forms.Form


{
GroupBox grpHolder;

public Exercise()
{
InitializeComponent();
}

private void InitializeComponent()


{
grpHolder = new GroupBox();
grpHolder.Left = 22;
grpHolder.Top = 18;
grpHolder.Width = 120;
grpHolder.Height = 58;
Controls.Add(grpHolder);
}
}

public class Program


{
static int Main()
{
System.Windows.Forms.Application.Run(new Exercise());
return 0;
}
}

This would produce:

Characteristics of a Group Box

C# 3.0 Practical Learning II 648


The Caption of a Group Box
As you can see from the above picture, a group may or may not display a
caption. If you need to display a caption on it, at design time, in the
Properties window, click Text and type a string. To do this programmatically,
assign a string to the Text property of the group box control. Here is an
example:
private void InitializeComponent()
{
grpHolder = new GroupBox();
grpHolder.Left = 22;
grpHolder.Top = 18;
grpHolder.Width = 120;
grpHolder.Height = 58;
grpHolder.Text = "Cup Holder";

Controls.Add(grpHolder);
}

This would produce:

The Group Box as a Container


Besides serving a delimiter of an area on a form, a group box can also serve
as a container. That is, a group box can carry or hold other containers. As
such, you can create a control and add it to its collection of controls. When
you add a control to a group box, whether at design or run time, the location
you specify is relative to the group box and not to the form. Because the
group box will act as the parent, it is its client area that is considered for the
location of its child(ren) control(s).

Here is an example of adding a control as a child of a group box:


private void InitializeComponent()
{
grpHolder = new GroupBox();
grpHolder.Left = 22;
grpHolder.Top = 18;
grpHolder.Width = 120;
grpHolder.Height = 58;
grpHolder.Text = "Cup Holder";

Button btnDone = new Button();


btnDone.Left = 22;

C# 3.0 Practical Learning II 649


btnDone.Top = 24;
grpHolder.Controls.Add(btnDone);

Controls.Add(grpHolder);
}

This would produce:

Automatically Resizing a Group Box


Since a group box can serve as a control container, at design time (and at run
time), you can add the desired controls to it. Here is an example:

Notice that it is possible to have a control whose size causes some of its
section to be hidden. To accommodate the control(s) positioned in a group
box, you can make the container resize itself so as to reveal the hidden
part(s) of its controls. To support this, the GroupBox class is equipped with
the Boolean AutoSize property. The default value of the
GroupBox.AutoSize property is false. If you set it to true, the group box
would resize itself and all of its controls should appear:

C# 3.0 Practical Learning II 650


Giving Focus to a Group Box
If you are done programming in Win32, you would know that the Microsoft
Windows operating system classifies the group box as a static controls. One
of characteristics of static controls is that they cannot receive focus. In other
words, you cannot actually click a group box and it cannot indicate that it has
received focus. At the same time, in the .NET Framework, the GroupBox class
is equipped with the TabStop and the TabIndex properties, which suggests
that, by pressing Tab while using a form that has a group box, the group box
should receive focus at one time. Still, because the group box is a static
control, it cannot receive focus. What actually happens is that, whenever a
group box is supposed to receive, it transfers the focus to its first or only
control.

Using a Mnemonic
As mentioned already, a group box can be equipped with a caption, which is
created by assigning a string to its Text property. A mnemonic is a character
(or a letter) that the user can use to access a group box. To create a
mnemonic, precede one character (or one letter) of its caption with &. Here is
an example:

C# 3.0 Practical Learning II 651


Using the mnemonic, the user can press Alt and the underlined character to
give focus to a control inside the group box.

Windows Control: The List View


 

Introduction
A list box is used to display a list of strings and all items of that control are
primarily strings. To go a little further than a simple list of strings, the
Microsoft Windows operating system provides the list view control. A list view
is used to display a list of items to the user but it can be configured to change
the type of display.

List View Creation


The list view control is made available in the .NET Framework through the
ListView class that is represented in the Windows Forms section of the
Toolbox by the list view button. To add a list view to your application, you
can click list view in the Toolbox and click the form or another container.

To programmatically create a list view, you can declare a variable of type


ListView, use the new operator to instantiate it and add it to its host's list of
controls through a call to the Controls.Add() method. Here is an example:
using System;
using System.Drawing;
using System.Windows.Forms;

public class Exercise : System.Windows.Forms.Form


{
ListView lvwCountries;

public Exercise()
{
InitializeComponent();
}

private void InitializeComponent()


{

C# 3.0 Practical Learning II 652


Text = "Countries Statistics";
Size = new Size(452, 218);

lvwCountries = new ListView();


lvwCountries.Location = new Point(12, 12);
lvwCountries.Width = 420;
lvwCountries.Height = 160;

Controls.Add(lvwCountries);
}
}

public class Program


{
static int Main()
{
System.Windows.Forms.Application.Run(new Exercise());
return 0;
}
}

After this declaration, an empty rectangular control is created and added to


your application. You can then start populating it.

Practical Learning: Introducing the Tree View Control

1. Start Microsoft Visual C#

2. Create a new Windows Application named DeptStore1

3. From the Common Controls section of the Toolbox, click ListView and
click the form

4. While the list view is still selected, in the Properties window, change the
(Name) to lvwStoreItems

C# 3.0 Practical Learning II 653


 

5. Save the form

Visually Creating the Items of a List


View
 

The Main Items of the List View


To create the items of a list view, you can use the ListViewItem Collection
Editor of Microsoft Visual Studio. To access it, after adding a list view object
to your application, you can click the ellipsis button of its Items field in the
Properties window:

C# 3.0 Practical Learning II 654


At design time and in the ListViewItem Collection Editor, to create a new
item, you can click the Add button.

Practical Learning: Visually Creating the Items of a List


View

1. On the form, click the list view.


In the Properties window, click Items and click its ellipsis button

2. In the ListViewItem Collection Editor, click Add

3. Under ListViewItem {} Properties, click Text and type 883095

4. Once again, click Add, click Text and type 602936

5. Once again, click Add, click Text and type 935709

6. Once again, click Add, click Text and type 200759

7. Once again, click Add, click Text and type 735633

8. Once again, click Add, click Text and type 492758


 

C# 3.0 Practical Learning II 655


9. Click OK

View Styles
To set it apart from the list box, a list view provides various options of
displaying its items. To support this, the ListView class is equipped with
the View property that is based on the View enumeration. Its members are:

 LargeIcon: In this view, the control displays a list of items in the order
they were added from left to right and from top to bottom. This means
that items start displaying on the top left section of the control to right.
When the first line is filled and there are still items, the list continues to
the next line. Each item uses a square size corresponding to a 32x32
pixel

 SmallIcon: Like the LargeIcon style, this view displays the list of items
from the left to the right then to the next line if necessary. This time,
each item uses a square region corresponding to a 16x16 pixel size

 List: Like the SmallIcon option, each item uses a 16x16 pixel square to
display. This time, the list is arranged in columns: the first item appears
to the left side of the control. The next item (usually in alphabetical
order) appears under it, and so on. If there are more items to fit in one
column, the list continues with a new column to the right of the previous
one. This continues until the list is complete

 Details: This view clearly sets the list view apart from the list box. In
this view, instead of showing just the string of the (main) item, each
item can provide more detailed information in a column

C# 3.0 Practical Learning II 656


As seen so far, you can use one of four different displays on a list view.
Furthermore, you can give the user the ability to change views as needed.
The different displays of the list view are controlled by the View property of
the ListView class. To specify the type of view to use, assign the desired
member of the View enumerator to the ListView.View property.

Practical Learning: Using View Styles

1. To create an icon, on the main menu, click Project -> Add New Item...

2. In the Templates list, click Icon File

3. Save the Name to LgIcon and click Add

4. Right-click the white area and click Delete Image Type

5. Design the 16x16 pixels version of the icon as follows:


 

6. Save and close the icon

7. On the main menu, click Project -> Add New Item...

8. In the Templates list, click Icon File

9. Save the Name to SmIcon and click Add

10. Right-click the white area and click Delete Image Type

11. Design the 16x16 pixels version of the icon as follows:


 

12. Save and close the icon

13. On the main menu, click Project -> Add New Item...

14. In the Templates list, click Icon File

15. Save the Name to List and click Add

C# 3.0 Practical Learning II 657


16. Right-click the white area and click Delete Image Type

17. Design the 16x16 version as follows:


 

18. Save and close the icon

19. On the main menu, click Project -> Add New Item...

20. In the Templates list, click Icon File

21. Save the Name to Details and click Add

22. Right-click the white area and click Delete Image Type

23. Design the 16x16 version as follows:


 

24. Save and close the icon

25. Change the design of the form as follows:


 

Control Name Appearance Checked Image AutoSize

C# 3.0 Practical Learning II 658


Label   Store Items      

RadioButton btnLargeIcons Button   LrgIcons.ico False

RadioButton btnSmallIcons Button   SmIcons.ico False

RadioButton btnList Button   List.ico False

RadioButton btnDetails Button True Details.ico False

Button btnClose Close      

26. Double-click the left button and implement its event as follows:
 
private void btnLargeIcons_CheckedChanged(object sender,
EventArgs e)
{
lvwStoreItems.View = View.LargeIcon;
}

27. Return to the form

28. Double-click the second button from left and implement its event as
follows:
 
private void btnSmallIcons_CheckedChanged(object sender,
EventArgs e)
{
lvwStoreItems.View = View.SmallIcon;
}

29. Return to the form

30. Double-click the third button from left and implement its event as
follows:
 
private void btnList_CheckedChanged(object sender, EventArgs e)
{
lvwStoreItems.View = View.List;
}

C# 3.0 Practical Learning II 659


31. Return to the form

32. Double-click the second button from right and implement its event as
follows:
 
private void btnDetails_CheckedChanged(object sender, EventArgs
e)
{
lvwStoreItems.View = View.Details;
}

33. Return to the form

34. Double-click the Close button and implement its Click events as follows:
 
private void btnClose_Click(object sender, EventArgs e)
{
Close();
}

35. Return to the form

36. Execute the application and click the buttons on the form

37. Close the form and return to your programming environment

List View Items and their Icons


One of the fundamental differences between a list box and a list view is that
this one has a built-in capability to display icons but this is only an option. The
list view uses two sets of pictures. This means that two icons would be
associated to each item. One of the icons should have a 32x32 pixels size and
the other should have a 16x16 pixels size. The set of 32x32 pixels list is
referred to as large icons. The other set is referred to as small icons. Before
using the pictures, you should first store them in image lists. Each set must
be stored in its own ImageList object.

To support the various sets of icons, the ListView class is equipped with a
property named LargeImageList for the 32x32 icons and another property
named SmallImageList for the 16x16 icons. After creating both ImageList
objects, you can assign each to the appropriate property.

After assigning the icons to the list view items, each view style can use the
appropriate item to display:

 LargeIcon: In this view, each item is displayed with its assigned 32x32
pixels icon. The string of the item displays under its corresponding icon:

C# 3.0 Practical Learning II 660


 

 List: Each item appears with the 16x16 pixels small icon to its left:
 

 SmallIcon: Like the List option, each item appears with the 16x16
pixels icon:

C# 3.0 Practical Learning II 661


  

 Details: Each item uses the 16x16 pixels icon

Practical Learning: Associating Icons With Nodes

1. To create an icon, on the main menu, click Project -> Add New Item...

2. In the Templates list, click Icon File

3. Set the Name to Babies and click Add

4. Design the icon as follows:


 

5. Right-click a white area in the main window -> Current Image Type ->
16x16, 16 colors

6. Design the icon as follows:


 

C# 3.0 Practical Learning II 662


7. On the main menu, click File -> Save Babies.ico

8. On the main menu, click File -> Close

9. On the main menu, click Project -> Add New Item...

10. In the Templates list, click Icon File

11. Set the Name to Teens and click Add

12. Design the icon as follows:


 

13. As done above, display the 16x16, 16 colors version of the icon and
design the icon as follows:
 

14. On the main menu, click File -> Save Teens.ico

15. On the main menu, click File -> Close

16. On the main menu, click Project -> Add New Item...

17. In the Templates list, click Icon File

18. Set the Name to Women and click Add

C# 3.0 Practical Learning II 663


19. Design it as follows:
 

20. Display its 16x16, 16 colors version and design it as follows:


 

21. On the main menu, click File -> Save Women.ico

22. On the main menu, click File -> Close

23. On the main menu, click Project -> Add New Item...

24. In the Templates list, click Icon File

25. Set the Name to Men and click Add

26. Design the icon as follows:


 

C# 3.0 Practical Learning II 664


27. Access its 16x16, 16 colors version and design it as follows:
 

28. On the main menu, click File -> Save Men.ico

29. On the main menu, click File -> Close

30. On the main menu, click Project -> Add New Item...

31. In the Templates list, click Icon File

32. Set the Name to Misc and click Add

33. Design the icon as follows:


 

34. Display its 16x16, 16 colors version and design it as follows:


 

35. On the main menu, click File -> Save Men.ico

36. On the main menu, click File -> Close

37. In the Toolbox, click ImageList and click the form

38. In the Properties window, change its name to imgLarge

39. Change the ImageSize to 32, 32

C# 3.0 Practical Learning II 665


40. Click the ellipsis button of the Images field

41. In Image Collection Editor, click Add

42. Locate the folder that contains the current project and display it in the
Look In combo box

43. Select Babies.ico and click Open

44. In the same way, add the other pictures in the following order:
Teens.ico, Women.ico, Men.ico, and Misc.ico

45. Click OK

46. In the Toolbox, click ImageList and click the form

47. In the Properties window, change its name to imgSmall

48. In the Properties window, click the ellipsis button of the Images field

49. In Image Collection Editor, click Add

50. Select Babies.ico, Teens.ico, Women.ico, Men.ico, and Misc.ico

51. Click OK

52. On the form, click the list view

53. In the Properties window, Set LargeImageList to imgLarge

54. Set the SmallImageList property to imgSmall

55. Click Items and click its ellipsis button

56. On the Members list, click the first item.


In the right list, click ImageIndex, then click the arrow of its combo box
and select 0

57. In the same way, assign the image indexes as follows:


 

Members ImageIndex

ListViewItem: {883095} 0

ListViewItem: {602936} 1

ListViewItem: {935709} 2

C# 3.0 Practical Learning II 666


ListViewItem: {200759} 3

ListViewItem: {735633} 2

ListViewItem: {492758} 4

58. Click OK
 

59. Execute the application to test it

60. Close the form and return to your programming environment

The Columns of a List View


 

Introduction
One of the characteristics that set the list view apart from the list box is that
the former can provide more information about each item of its list. Based on
this, each type of item can be equipped with its own list of sub-items. The
view would appear as follows:

C# 3.0 Practical Learning II 667


Visually Creating Columns
Before creating the sub-items of a list view, you may need to plan it first to
identify the types of information you want to provide. To guide the user with
the type of information that each item would display, you can create a column
for each type. To support columns, the ListView class is equipped with the
Columns property. The Columns property is an object of type
ListView.ColumnHeaderCollection. As its name indicates, the Columns
property represents a list of columns. Each column is based on the
ColumnHeader class.

At design time, to create the columns, access the Properties window for the
list view and click the ellipsis button of the Columns field. This would open the
ColumnHeader Collection Editor. To create a column, you can click Add. In
the right Properties list, you can click Text and type the string that would
display on the column header.

Programmatically Creating Columns


To programmatically create a column, you can call the
ColumnHeaderCollection.Add() method that is overloaded with two
versions. One of the versions of this method uses the following syntax:
public virtual ColumnHeader Add(string caption, int width,
HorizontalAlignment textAlign);

The first argument of this method is referred to as the column's caption. It is


text that would display in the column header. The second argument is a
natural number that represents the distance from the left to the right borders
of the column. The last argument specifies how the caption of the column
would be aligned. The options are the same as those of the text box: Left,
Center, or Right. The default value is Left.

Here is an example of creating a column by calling this method:

C# 3.0 Practical Learning II 668


private void InitializeComponent()
{
Text = "Countries Statistics";
Size = new Size(452, 214);

lvwCountries = new ListView();


lvwCountries.Location = new Point(12, 12);
lvwCountries.Width = 420;
lvwCountries.Height = 160;

lvwCountries.View = View.Details;
lvwCountries.Columns.Add("Name", 120,
HorizontalAlignment.Left);

Controls.Add(lvwCountries);
}

This would produce:

As mentioned earlier, a column is in fact an object of type ColumnHeader.


This class is equipped with all the necessary characteristics that define a
column header:

 Caption: The Text property holds the string that displays on top of the
column

 Width: This property represents the width of the column

 Text Alignment: The TextAlign property specifies the horizontal


alignment of its string. This property uses a value of type
HorizontalAlignment, which is the same as that of the text box

 Index: Since the columns are stored in a collection, this property allows
you to get the index of this column in the collection it belongs to

 The Parent List View: If you want to know what list view the current
column header belongs to, you can access its ColumnHeader.ListView
property

C# 3.0 Practical Learning II 669


Instead of defining a column in the Add() method, you can first create an
object based on the ColumnHeader class and then pass it to the following
version of the ColumnHeaderCollection.Add() method:
public virtual int Add(ColumnHeader value);

This method takes as argument a ColumnHeader object. Here is an example:


private void InitializeComponent()
{
Text = "Countries Statistics";
Size = new Size(452, 214);

lvwCountries = new ListView();


lvwCountries.Location = new Point(12, 12);
lvwCountries.Width = 420;
lvwCountries.Height = 100;

lvwCountries.View = View.Details;
lvwCountries.Columns.Add("Name", 120,
HorizontalAlignment.Left);

ColumnHeader colArea = new ColumnHeader();


colArea.Text = "Area";
colArea.Width = 80;
colArea.TextAlign = HorizontalAlignment.Right;
lvwCountries.Columns.Add(colArea);

Controls.Add(lvwCountries);
}

This would produce:

Instead of adding one column at a time as we have done above, you can first
create an array of ColumnHeader objects and pass it to the
ListView.ColumnHeaderCollection.AddRange() method. Its syntax is:

public virtual void AddRange(ColumnHeader values[]);

Here is an example of using it:


private void InitializeComponent()
{
Text = "Countries Statistics";
Size = new Size(452, 214);

C# 3.0 Practical Learning II 670


lvwCountries = new ListView();
lvwCountries.Location = new Point(12, 12);
lvwCountries.Width = 420;
lvwCountries.Height = 100;

lvwCountries.View = View.Details;
lvwCountries.Columns.Add("Name", 120,
HorizontalAlignment.Left);

ColumnHeader colArea = new ColumnHeader();


colArea.Text = "Area";
colArea.Width = 80;
colArea.TextAlign = HorizontalAlignment.Right;
lvwCountries.Columns.Add(colArea);

ColumnHeader colPopulation = new ColumnHeader();


colPopulation.Text = "Population";
colPopulation.Width = 78;
colPopulation.TextAlign = HorizontalAlignment.Right;

ColumnHeader colCapital = new ColumnHeader();


colCapital.Text = "Capital";
colCapital.Width = 96;
colCapital.TextAlign = HorizontalAlignment.Left;

ColumnHeader colCode = new ColumnHeader();


colCode.Text = "Code";
colCode.Width = 40;
colCode.TextAlign = HorizontalAlignment.Center;

ColumnHeader[] cols = { colPopulation, colCapital,


colCode };
lvwCountries.Columns.AddRange(cols);

Controls.Add(lvwCountries);
}

This would produce:

Practical Learning: Creating Columns

1. On the form, click the list view

C# 3.0 Practical Learning II 671


2. In the Properties window, click Columns and click its ellipsis button

3. In the ColumnHeader Collection Editor, click Add

4. In the columnHeader1 properties list, change the following properties


(Name): colItemNumber
Text: Item #
Width: 70

5. Click Add again and set the new column as follows:


(Name): colCategory
Text: Category
Width: 70

6. Click Add again and set the new column as follows:


(Name): colItemName
Text: Item Name
Width: 180

7. Click Add again and set the new column as follows:


(Name): colItemSize
Text: Size
Width: 80

8. Click Add again and set the new column as follows:


(Name): colUnitPrice
Text: Unit Price
TextAlign: Right

9. Click Add again and set the new column as follows:


(Name): colQuantity
Text: Qty
TextAlign: Right
Width: 40

10. Click OK

11. While the list view is still selected in the form, change its View property
to Details
  

C# 3.0 Practical Learning II 672


12. Execute the application to test it

13. After viewing the form, close it and return to your programming
environment

Column Insertion
If you call the AddRange() method, its list of columns is created at the end of
any existing column, unless there was no other column. If you call the Add()
method to create a column, the new column is added at the end of the
existing columns, unless it is the first column. If you don't want the new
column to simply be created at the end of the other column(s), if any, you
can call the ColumnHeaderCollection.Insert() method. It is overloaded
with two versions and their syntaxes are:
public void Insert(int index, ColumnHeader value);
public void Insert(int index, string str, int width,
HorizontalAlignment textAlign);

In both versions, the first argument specifies the index where the new column
will be created inside the Columns collection.

Practical Learning: Using a List View

1. To start a new project, on the main menu, click File -> New -> Project...

2. In the Templates list, click Windows Application and set the Name to
AltairRealtors2

3. Design the form as follows:


 

C# 3.0 Practical Learning II 673


Control Text Name Other Properties

BorderStyle:
FixedSingle
Altair Realtors -
Label   Font: Times New
Properties Listing
Roman, 21.75pt,
style=Bold

ListView   lvwProperties  

(Name) Text TextAlign Width

colPropertyNumber Prop #   50

colPropertyType Property Type   78

colAddress Address   130

colCity City   80
Columns
colState State   40

colZIPCode ZIP Code Center 58

colBedrooms Beds Right 40

colBathrooms Baths Right 40

colMarketValue Market Value Right 75

Button New Property... btnNewProperty  

Button Close btnClose  

4. Save the form

C# 3.0 Practical Learning II 674


The Number of Columns of a List View
As reviewed above, the columns of a list view are stored in a collection. To
know the number of columns of a list view, you can check its
ColumnHeaderCollection.Count property.

Locating Columns
To find out if a certain column is part of a list view, you can call the
ColumnHeaderCollection.Contains() method. Its syntax is:

public bool Contains(ColumnHeader value);

This method takes as argument a defined ColumnHeader object and scans


the list of columns looking for it. If it finds it, it returns true. If it doesn't find
a column that matches this object, it returns false. As opposed to looking for
a column, you can perform two searches in one by calling the
ColumnHeaderCollection.IndexOf() method. Its syntax is:

public int IndexOf(ColumnHeader value);

This method looks for the value ColumnHeader. If it finds it, it returns the
column's index from the collection. If the method doesn't find it, it returns -1.

Deleting Columns
If you don't need a column any more, you can delete it. In the same way, you
can delete all columns of a list view. To delete a ColumnHeader object, you
can call the ColumnHeaderCollection.Remove() method. Its syntax is:
public virtual void Remove(ColumnHeader column);

To delete a column based on its position in the collection, you can call the
ColumnHeaderCollection.RemoveAt() method. Its syntax is:

public virtual void RemoveAt(int index);

To delete all columns of a list


view, you can call the
ListView.ColumnHeaderCollection.Clear() method. Its syntax is:

public virtual void Clear();

The Items of a List View


 

C# 3.0 Practical Learning II 675


Adding an Item to the List View 
In the previous sections, we saw how to visually create the items of a list
view using the ListViewItem Collection Editor. The items of a list view are
stored in a property called Items. The Items property is based on the
ListView.ListViewItemCollection class. The nested
ListViewItemCollection class implements the IList, the ICollection,
and the IEnumerable interfaces.

To create a new list view item, the ListViewItemCollection class is


equipped with the Add() method which is overloaded with three versions.
One of the versions of this method uses the following syntax:

public virtual ListViewItem Add(string text);

This method expects a string that will display as the new item. Here is an
example:
private void InitializeComponent()
{
Text = "Countries Statistics";
Size = new Size(452, 214);

lvwCountries = new ListView();


lvwCountries.Location = new Point(12, 12);
lvwCountries.Width = 420;
lvwCountries.Height = 160;

lvwCountries.Items.Add("Egypt");

Controls.Add(lvwCountries);
}

This would produce:

C# 3.0 Practical Learning II 676


As the Items property is in fact a list, each item of this collection is
represented by the Item property of the ListViewItemCollection class.
This Item property is based on the ListViewItem class. The ListViewItem
class is equipped with various constructors, the default of which allows you to
instantiate an item without giving much details.

Instead of directly passing a string to the ListViewItemCollection.Add()


method, you can first create a ListViewItem object and pass it to the
following version of the ListViewItemCollection.Add() method:
public virtual ListViewItem Add(ListViewItem value);

This method expects a ListViewItem value. One way you can use it consists
of providing the string the item would display. To do this, you can use the
following constructor of the ListViewItem class:
public ListViewItem(string text);

This constructor expects as argument the text that the new item will display.
Here is an example:
private void InitializeComponent()
{
Text = "Countries Statistics";
Size = new Size(452, 214);

lvwCountries = new ListView();


lvwCountries.Location = new Point(12, 12);
lvwCountries.Width = 420;
lvwCountries.Height = 160;

lvwCountries.Items.Add("Egypt");

ListViewItem lviPortugal = new ListViewItem("Portugal");

lvwCountries.Items.Add(lviPortugal);

Controls.Add(lvwCountries);
}

C# 3.0 Practical Learning II 677


Practical Learning: Creating List View Items

1. On the main menu, click Project -> Add Windows Form...

2. Set the Name to AvailableProperty and click Add

3. Design the form as follows:


 

Control

Text Name Other Properties

Property
Label    
#:

TextBox   txtPropertyNumber Modifiers: Public

Button OK btnOK DialogResult: OK

DialogResult:
Button Cancel btnCancel
Cancel

Form

FormBorderStyle: FixedDialog

Text: Altair Realtors - Available Property

StartPosition: CenterScreen

AcceptButton: btnOK

CancelButton: btnCancel

C# 3.0 Practical Learning II 678


MaximizeBox: False

MinimizeBox: False

ShowInTaskBar: False

4. In the Solution Explorer, right-click Form1.cs and click Rename

5. Type AltairRealtor.cs and press Enter twice

6. On the form, double-click the New Property button and implement its
event as follows:
 
private void btnNewProperty_Click(object sender, EventArgs e)
{
AvailableProperty dlgProperty = new AvailableProperty();

Random rndNumber = new Random(DateTime.Now.Millisecond);


int number1 = rndNumber.Next(100, 999);
int number2 = rndNumber.Next(100, 999);
string propNumber = number1 + "-" + number2;

dlgProperty.txtPropertyNumber.Text = propNumber;
dlgProperty.Text = "Altair Realtors - New Property";

if (dlgProperty.ShowDialog() == DialogResult.OK)
{
ListViewItem lviStoreItem =
new
ListViewItem(dlgProperty.txtPropertyNumber.Text);
lvwProperties.Items.Add(lviStoreItem);
}
}

7. Execute the application to test it

8. When the form displays, click the New Property button and, when the
dialog box comes up, click OK

9. Do this five times to create five items


 

C# 3.0 Practical Learning II 679


10. Close the form and return to your programming environment

Adding an Array of Items


You can use any of these techniques to create as many items as necessary.
Alternatively, if you have many items to create, you can first store them in an
array of ListViewItem values, then call the AddRange() method. The syntax
of this method is:
public void AddRange(ListViewItem[] items);

This method takes as argument an array of ListViewItem objects. Here is an


example:
private void InitializeComponent()
{
Text = "Countries Statistics";
Size = new Size(452, 214);

lvwCountries = new ListView();


lvwCountries.Location = new Point(12, 12);
lvwCountries.Width = 420;
lvwCountries.Height = 160;

lvwCountries.Items.Add("Egypt");

ListViewItem lviPortugal = new ListViewItem("Portugal");


lvwCountries.Items.Add(lviPortugal);

ListViewItem[] lviCountries =
{

new ListViewItem("Australia"),

new ListViewItem("Mali"),

C# 3.0 Practical Learning II 680


new ListViewItem("Sweden"),

new ListViewItem("Venezuela")

};

lvwCountries.Items.AddRange(lviCountries);

Controls.Add(lvwCountries);
}

Alternatively, you can create an array of strings and pass it to the following
constructor of the ListView class:
public ListViewItem(string[] items);

Using a List View


 

Selecting an Item From the List View 


As mentioned previously, a list view is made of a list of items. An item can be
identified by its index:

 On a large image or a small image style, the item on the top-left side has
an index of 0. The second item from the left has an index of 1, and so
on, up to the subsequent lines, if any

C# 3.0 Practical Learning II 681


 On a list style, the top item on the left column has an index of 0. The
second item from top on the left column has an index of 1, and so on,
up to the subsequent columns, if any

 On a details style, the most top item has an index of 0. The second item
from the top has an index of 1, and so on 

When a list view comes up, it displays its list of items. To use an item, the
user can click it. When an item has been clicked, the control fires a
SelectedIndexChanged event. The SelectedIndexChanged event is of type
EventArgs, which means it does not carry any significant information except
to let you know that an item has been clicked. Worse, this event does not
even let you know the index of the item that was clicked. This means that
you must work on your own to identify the item that was clicked.

When the user clicks an item, you can use a technique to identify the item
that was selected, when another item gets selected, the the item that was
previously selected fires an ItemSelectionChanged event.

Editing a Label
Clicking an item once allows the user to select it. You may create an
application that allows the user to edit an item, that is, to change the string
that the item displays. To edit an item, the user can click (once) an item, then
click (once) the item again. This puts it into edit mode. The user can then use
the keyboard to change the string of the item:

To support the ability to let the user edit an item, the ListView class is
equipped with the LabelEdit Boolean property. The default value of this
property is false, which would prevent the user from editing the item in the
list view. If you set this property to true, the user can click, then click the
item to edit it.

C# 3.0 Practical Learning II 682


When the user starts editing, the control fires a BeforeLabelEdit event.
This event allows you to take care of some early processing, such as checking
what the user is doing or canceling the editing.

If you allow the user to edit the item, after the user has edited it, the control
fires an AfterLabelEdit event. 

Both the BeforeLabelEdit and the AfterLabelEdit events are of type


LabelEditEventArgs. One of the pieces of information that this class
provides is the index of the item that is being edited. This index is held by the
Item property of the LabelEditEventArgs class. To get the string resulting
from the user editing, the LabelEditEventArgs class is equipped with the
Label property. When the control fires a BeforeLabelEdit or the a
AfterLabelEdit event, to help you decide whether to accept or reject the
change, the LabelEditEventArgs class is equipped with the CancelEdit
Boolean property.

Activating an Item
When an item has been selected, it becomes highlighted. If you use the
LabelEdit property to allow the user to edit an item, this is a local edition.
In the next sections, we will learn how to add sub-items to a list view item.
When an item is equipped with sub-items, you may want your application to
allow the user to change the item, one of its sub-items, or everything. Before
doing anything, an item must be activated. There are three ways an item has
been activated.

The technique used to activate an item is supported by the Activation


property. The Activation property is based on the ItemActivation
enumeration that has three members:

 Standard: When the Activation property is set to Standard, to


activate an item, the user must double-click the item

 OneClick: With this option, the user would click an item once to active it

 TwoClick: If you set the Activation property to this member, the user
would have to click the item, then click it again to activate it (clicking
once and clicking again once is not the same as double-clicking)

When an item has been activated, the control fires an ItemActivate event.
You can use either this or the SelectedIndexChanged event to process the
item.

Practical Learning: Using a List View

1. Display the first form AltairRealtor.cs [Design] and, on the form, click the
list view

C# 3.0 Practical Learning II 683


2. In the Properties section of the Properties window, click Activation and
make sure it is set to Standard.
Click the Events button and double-click DoubleClick

3. Implement its event as follows:


 
private void lvwProperties_DoubleClick(object sender, EventArgs
e)
{
// Prepare to open the AvailableProperties dialog
box
AvailableProperty dlgProperty = new
AvailableProperty();

// Make sure an item, and only one, is selected


if ((lvwProperties.SelectedItems.Count == 0) ||
(lvwProperties.SelectedItems.Count > 1))
return;

// Identify the item that is currently selected


ListViewItem lviCurrent =
lvwProperties.SelectedItems[0];

// Display the ItemDetails dialog box with the item


number
dlgProperty.txtPropertyNumber.Text =
lviCurrent.Text;
dlgProperty.ShowDialog();
}

4. Execute the application to test it

5. Click the New Item button followed by the OK button a few times

6. Then double-click a number in the list view

7. Close the form and return to your programming environment

Using Columns
Besides the items, the user can also use the columns. For example, you can
allow the user to re-arrange or sort the list of items with the user clicks a
column. When the user a column header, the control fires a ColumnClick
event. The ColumnClick event is of type ColumnClickEventArgs. The
ColumnClickEventArgs class is equipped with the Column integer property
that allows you to identify the index of the column that was clicked.

Besides clicking a column header, the user can also resize a column by
dragging the line separator between two columns. If the user decides to
resize a column and starts dragging the line separator, the control fires
ColumnWidthChanging event. After the user has resized a column, the
control fires a ColumnWidthChanged event.

C# 3.0 Practical Learning II 684


Identifying an Item
The only actual property that the nested ListViewItemCollection class is
equipped with is the default Item property. This property allows you to
identify an item. There are two versions of the Item property. You can
identify an item using its index, which is its zero-based position. As an
alternative, you can identify an item using its string.

The Sub Items of an Item


 

Introduction 
The idea of having columns is to provide more information about each item of
a list view instead of a simple string for each. Consider the following example:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace WinForms1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

private void Form1_Load(object sender, EventArgs e)


{
lvwCountries.View = View.Details;

lvwCountries.Columns.Add("Name", 120,
HorizontalAlignment.Left);
ColumnHeader colArea = new ColumnHeader();
colArea.Text = "Area";
colArea.Width = 80;
colArea.TextAlign = HorizontalAlignment.Right;
lvwCountries.Columns.Add(colArea);

ColumnHeader colPopulation = new ColumnHeader();

C# 3.0 Practical Learning II 685


colPopulation.Text = "Population";
colPopulation.Width = 78;
colPopulation.TextAlign = HorizontalAlignment.Right;

ColumnHeader colCapital = new ColumnHeader();


colCapital.Text = "Capital";
colCapital.Width = 96;
colCapital.TextAlign = HorizontalAlignment.Left;

ColumnHeader colCode = new ColumnHeader();


colCode.Text = "Code";
colCode.Width = 40;
colCode.TextAlign = HorizontalAlignment.Center;

ColumnHeader[] cols = { colPopulation, colCapital,


colCode };
lvwCountries.Columns.AddRange(cols);

lvwCountries.Items.Add("Egypt");

ListViewItem lviPortugal = new


ListViewItem("Portugal");
lvwCountries.Items.Add(lviPortugal);

ListViewItem lviCountry = new


ListViewItem("Australia");
lvwCountries.Items.Add(lviCountry);
lviCountry = new ListViewItem("Mali");
lvwCountries.Items.Add(lviCountry);
lviCountry = new ListViewItem("Sweden");
lvwCountries.Items.Add(lviCountry);
}
}
}

This would produce:

Visually Creating Sub Items


To visually create the sub-items, you must use the ListViewSubItem Collection
Editor. To get it, first access the Properties window of the list view and click
the ellipsis button of the Items field. As mentioned previously, this would
open the ListView Collection Editor. From that dialog box, you can click the
ellipsis button of the SubItems field.

C# 3.0 Practical Learning II 686


When the ListViewSubItem Collection Editor comes up, to create a sub-item
of the current item, you can click Add. Then, on the right side, define the
characteristics of the sub-items. You can continue this until you have created
all necessary sub-items.

Practical Learning: Visually Creating Sub Items

1. Re-open the DeptStore1 application

2. On the form, click the list view

3. In the Properties window, click Items and click its ellipsis button

4. In the ListView Collection Editor, as the first item is selected, on the right
side, click SubItems and click its ellipsis button

5. In the ListViewSubItem Collection Editor, click Add

6. On the right side, click Text and type Babies

7. Click Add again

8. On the right side, click Text and type Newborn Girl's Dress Set

9. Click Add again

10. On the right side, click Text and type 6 Months

11. Click Add again

12. On the right side, click Text and type 19.95

13. Click Add again

C# 3.0 Practical Learning II 687


14. On the right side, click Text and type 12
 

15. Click OK

16. Click each item and complete its sub-items with the following:
  

Unit
Category Item Name Size Qty
Price

Teens Girls Classy Handbag One Size 95.95 4

Women Cashmere Lined Glove 8 115.95 12

Men Trendy Jacket Medium 45.85 8

Women Stretch Flare Jeans Petite 27.75 6

Miscellaneous Chocolate Gift Box Medium 45.00 5

C# 3.0 Practical Learning II 688


17.  

18. Close the form and return to your programming environment

Programmatically Creating Sub Items


To support sub-items, the ListViewItem class is equipped with a property
called SubItems. This property is of type ListViewSubItemCollection. To
create a sub-item, you can directly specify its text by passing a string to the
ListViewSubItemCollection.Add() method. The
ListViewSubItemCollection.Add() method is overloaded with three
versions. The version referred to in this case uses the following syntax:
public ListViewSubItem Add(string text);

To identify each piece of


information concerning a sub-item, the
ListViewSubItemCollection class is equipped with a property called Item,
which in turn is based on the ListViewSubItem class. As you can see, the
above Add() method returns a ListViewSubItem value.

Here are two examples of calling the above Add() method:


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace WinForms1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

C# 3.0 Practical Learning II 689


private void Form1_Load(object sender, EventArgs e)
{
lvwCountries.View = View.Details;

lvwCountries.Columns.Add("Name", 120,
HorizontalAlignment.Left);
ColumnHeader colArea = new ColumnHeader();
colArea.Text = "Area";
colArea.Width = 80;
colArea.TextAlign = HorizontalAlignment.Right;
lvwCountries.Columns.Add(colArea);

ColumnHeader colPopulation = new ColumnHeader();


colPopulation.Text = "Population";
colPopulation.Width = 78;
colPopulation.TextAlign = HorizontalAlignment.Right;

ColumnHeader colCapital = new ColumnHeader();


colCapital.Text = "Capital";
colCapital.Width = 96;
colCapital.TextAlign = HorizontalAlignment.Left;

ColumnHeader colCode = new ColumnHeader();


colCode.Text = "Code";
colCode.Width = 40;
colCode.TextAlign = HorizontalAlignment.Center;

ColumnHeader[] cols = { colPopulation, colCapital,


colCode };
lvwCountries.Columns.AddRange(cols);

ListViewItem lviEgypt =
lvwCountries.Items.Add("Egypt");
lviEgypt.SubItems.Add("1,001,450");
lviEgypt.SubItems.Add("74,718,797");
lviEgypt.SubItems.Add("Cairo");
lviEgypt.SubItems.Add("eg");

ListViewItem lviPortugal = new


ListViewItem("Portugal");
lviPortugal.SubItems.Add("92,391");
lviPortugal.SubItems.Add("10,102,022");
lviPortugal.SubItems.Add("Lisbon");
lviPortugal.SubItems.Add("pt");
lvwCountries.Items.Add(lviPortugal);

ListViewItem lviCountry = new


ListViewItem("Australia");
lvwCountries.Items.Add(lviCountry);
lviCountry = new ListViewItem("Mali");
lvwCountries.Items.Add(lviCountry);
lviCountry = new ListViewItem("Sweden");
lvwCountries.Items.Add(lviCountry);
}
}

C# 3.0 Practical Learning II 690


}

This would produce:

As mentioned above, each sub-item is of type ListViewSubItem. The


ListViewSubItem class is equipped with three constructors. The default
constructor allows you to create an empty sub-item. After declaring a sub-
item, you can specify its text by assigning the desired string to the
ListViewSubItem.Text property. Instead of directly passing the text of a
sub-item to the ListViewSubItemCollection.Add() method as done
above, you can first define a ListViewSubItem object using the following
constructor of the ListViewSubItem class:
public ListViewSubItem(ListViewItem owner, string text);

The first argument of this constructor specifies the ListViewItem object that
this sub-item will belong to. The second argument is simply the string that
this sub-item will display. After defining a ListViewSubItem object, you can
pass it to the following version of the ListViewSubItemCollection.Add()
method:
public ListViewSubItem Add(ListViewItem.ListViewSubItem item);

Here are three examples of using it:


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace WinForms1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

private void Form1_Load(object sender, EventArgs e)


{

C# 3.0 Practical Learning II 691


lvwCountries.View = View.Details;

lvwCountries.Columns.Add("Name", 120,
HorizontalAlignment.Left);
ColumnHeader colArea = new ColumnHeader();
colArea.Text = "Area";
colArea.Width = 80;
colArea.TextAlign = HorizontalAlignment.Right;
lvwCountries.Columns.Add(colArea);

ColumnHeader colPopulation = new ColumnHeader();


colPopulation.Text = "Population";
colPopulation.Width = 78;
colPopulation.TextAlign = HorizontalAlignment.Right;

ColumnHeader colCapital = new ColumnHeader();


colCapital.Text = "Capital";
colCapital.Width = 96;
colCapital.TextAlign = HorizontalAlignment.Left;

ColumnHeader colCode = new ColumnHeader();


colCode.Text = "Code";
colCode.Width = 40;
colCode.TextAlign = HorizontalAlignment.Center;

ColumnHeader[] cols = { colPopulation, colCapital,


colCode };
lvwCountries.Columns.AddRange(cols);

ListViewItem lviEgypt =
lvwCountries.Items.Add("Egypt");
lviEgypt.SubItems.Add("1,001,450");
lviEgypt.SubItems.Add("74,718,797");
lviEgypt.SubItems.Add("Cairo");
lviEgypt.SubItems.Add("eg");

ListViewItem lviPortugal = new


ListViewItem("Portugal");
lviPortugal.SubItems.Add("92,391");
lviPortugal.SubItems.Add("10,102,022");
lviPortugal.SubItems.Add("Lisbon");
lviPortugal.SubItems.Add("pt");
lvwCountries.Items.Add(lviPortugal);

ListViewItem lviAustralia = new


ListViewItem("Australia");
ListViewItem.ListViewSubItem subAustralia =
new ListViewItem.ListViewSubItem(lviAustralia,
"7,686,850");
lviAustralia.SubItems.Add(subAustralia);
subAustralia =
new ListViewItem.ListViewSubItem(lviAustralia,
"19,731,984");
lviAustralia.SubItems.Add(subAustralia);
subAustralia =

C# 3.0 Practical Learning II 692


new ListViewItem.ListViewSubItem(lviAustralia,
"Canberra");
lviAustralia.SubItems.Add(subAustralia);
subAustralia = new
ListViewItem.ListViewSubItem(lviAustralia, "au");
lviAustralia.SubItems.Add(subAustralia);
lvwCountries.Items.Add(lviAustralia);

ListViewItem lviMali = new ListViewItem("Mali");


ListViewItem.ListViewSubItem subMali =
new ListViewItem.ListViewSubItem(lviMali, "1.24
million");
lviMali.SubItems.Add(subMali);
subMali = new ListViewItem.ListViewSubItem(lviMali,
"11,626219");
lviMali.SubItems.Add(subMali);
subMali = new ListViewItem.ListViewSubItem(lviMali,
"Bamako");
lviMali.SubItems.Add(subMali);
subMali = new ListViewItem.ListViewSubItem(lviMali,
"ml");
lviMali.SubItems.Add(subMali);
lvwCountries.Items.Add(lviMali);

ListViewItem lviSweden = new ListViewItem("Sweden");


ListViewItem.ListViewSubItem subSweden =
new ListViewItem.ListViewSubItem(lviSweden,
"449,964");
lviSweden.SubItems.Add(subSweden);
subSweden = new
ListViewItem.ListViewSubItem(lviSweden, "8,878,085");
lviSweden.SubItems.Add(subSweden);
subSweden = new
ListViewItem.ListViewSubItem(lviSweden, "Stockholm");
lviSweden.SubItems.Add(subSweden);
subSweden = new
ListViewItem.ListViewSubItem(lviSweden, "se");
lviSweden.SubItems.Add(subSweden);
lvwCountries.Items.Add(lviSweden);
}
}
}

This would produce:

C# 3.0 Practical Learning II 693


If you call the ListViewSubItemCollection.Add() method to create a sub-
item, the new sub-item would be added to end of the list. If you want, you
can insert the new sub-item somewhere inside the collection. To do this, you
would call the ListViewSubItemCollection.Insert() method. Its syntax
is:
public void Insert(int index, ListViewItem.ListViewSubItem
item);

The first argument is the index that the new sub-item will occupy after being
inserted. The second argument is the sub-item to create.

Practical Learning: Creating Sub-Items

1. Re-open the AltairRealtors2 application

2. Display the AvailableProperty form and change its design as follows:


 

Control

Text Name Other Properties

Label Property #:    

TextBox   txtPropertyNumber Modifiers: Public

Property
Label    
Type:

C# 3.0 Practical Learning II 694


Modifiers:
Public
Items:
ComboBox   cbxPropertyTypes Unknown
Single Family
Townhouse
Condominium

Label Address:    

TextBox   txtAddress Modifiers: Public

Label City:    

TextBox   txtCity Modifiers: Public

Label State:    

Modifiers: Public
Items:
DC
ComboBox   cbxStates MD
PA
VA
WV

Label ZIP Code:    

TextBox   txtZIPCode Modifiers: Public

Label Bedrooms:    

TextBox 0 txtBedrooms Modifiers: Public

C# 3.0 Practical Learning II 695


Label Bathrooms:    

TextBox 1.0 txtBathrooms Modifiers: Public

Label Market Value:    

TextBox 0.00 txtMarketValue Modifiers: Public

Button OK btnOK DialogResult: OK

DialogResult:
Button Cancel btnCancel
Cancel

Form

FormBorderStyle: FixedDialog

Text: Altair Realtors - Available Property

StartPosition: CenterScreen

AcceptButton: btnOK

CancelButton: btnCancel

MaximizeBox: False

MinimizeBox: False

ShowInTaskBar: False

3. Display the first form

4. On the (first) form, double-click the New Item button and change its
Click event as follows:
 
private void btnNewProperty_Click(object sender, EventArgs e)
{

C# 3.0 Practical Learning II 696


AvailableProperty dlgProperty = new AvailableProperty();

Random rndNumber = new Random(DateTime.Now.Millisecond);


int number1 = rndNumber.Next(100, 999);
int number2 = rndNumber.Next(100, 999);
string propNumber = number1 + "-" + number2;

dlgProperty.txtPropertyNumber.Text = propNumber;
dlgProperty.Text = "Altair Realtors - New Property";

if (dlgProperty.ShowDialog() == DialogResult.OK)
{
string strPropertyType =
dlgProperty.cbxPropertyTypes.Text;
string strAddress = dlgProperty.txtAddress.Text;
string strCity = dlgProperty.txtCity.Text;
string strState = dlgProperty.cbxStates.Text;
string strZIPCde = dlgProperty.txtZIPCode.Text;
string strBedrooms = dlgProperty.txtBedrooms.Text;
string strBathrooms = dlgProperty.txtBathrooms.Text;
string strMarketValue = dlgProperty.txtMarketValue.Text;

ListViewItem lviProperty =
new
ListViewItem(dlgProperty.txtPropertyNumber.Text);

lviProperty.SubItems.Add(strPropertyType);
lviProperty.SubItems.Add(strAddress);
lviProperty.SubItems.Add(strCity);
lviProperty.SubItems.Add(strState);
lviProperty.SubItems.Add(strZIPCde);
lviProperty.SubItems.Add(strBedrooms);
lviProperty.SubItems.Add(strBathrooms);
lviProperty.SubItems.Add(strMarketValue);
lvwProperties.Items.Add(lviProperty);
}
}

5. Execute the application and create a few properties as follows (the


computer will generate the properties numbers)
 

C# 3.0 Practical Learning II 697


6. Close the form and return to your programming environment

Managing Sub Items


When you create a new sub-item, it uses a default font and a black color on a
white background. If you want, you can change the way a sub-item
aesthetically displays. To allow these changes, the ListViewItem class is
equipped with the UseItemStyleForSubItems Boolean property, whose
default value is true. When this property is set to true, the compiler refers to
the item that "owns" the current sub-item to paint the sub-item, as we will
see in the next section. If you plan to change these aspects, you must first
set this property to false.

After setting the ListViewItem.UseItemStyleForSubItems property to


false, you can set the following properties of the ListViewSubItem class as
you wish:

 Font: This allows you to apply a font of your choice for a particular sub-
item. This would be done as follows:
 
ListViewItem lviSweden = new ListViewItem("Sweden");
lviSweden.UseItemStyleForSubItems = false;
ListViewItem.ListViewSubItem subSweden =
new ListViewItem.ListViewSubItem(lviSweden, "449,964");
. . .
subSweden = new ListViewItem.ListViewSubItem(lviSweden,
"Stockholm");
subSweden.Font = new Font("Times New Roman", 14,
FontStyle.Italic);
lviSweden.SubItems.Add(subSweden);
. . .

C# 3.0 Practical Learning II 698


 ForeColor: Instead writing a sub-item's text in black, you can assign the desired
color to this property to use a different color. This would be done as follows:
 
ListViewItem.ListViewSubItem subSweden =
new ListViewItem.ListViewSubItem(lviSweden, "449,964");
subSweden.ForeColor = Color.Red;
lviSweden.SubItems.Add(subSweden);

 BackColor: This property allows an individual sub-item to display on top


of a specify color. This would be done as follows:
 
subSweden = new ListViewItem.ListViewSubItem(lviSweden,
"8,878,085");
subSweden.BackColor = Color.Blue;
lviSweden.SubItems.Add(subSweden);

To restore these settings on the sub-item, you can call the


ListViewItem.ListViewSubItem.ResetStyle() method. Its syntax is:

public void ResetStyle();

When called, this method resets the font, the text color, and the background
color.

C# 3.0 Practical Learning II 699


Managing the Items of a List View
 

The Font, Text Color, and Background of an Item


After adding an item to a list view, the new item assumes some default styles
involving the font, the color, and the background. To enhance the appearance
of the items, you can change these characteristics that are primarily
controlled by the ListViewItem.UseItemStyleForSubItems Boolean
property. Its default value is true. You can use it to change the properties of
an item as follows:

 Font: If you assign a new font to the item, this property allows you to
apply a font of your choice to a particular sub-item. This would be done
as follows:
 
. . .
ListViewItem lviAustralia = new ListViewItem("Australia");
lviAustralia.Font = new Font("Georgia", 8, FontStyle.Bold);
ListViewItem.ListViewSubItem subAustralia =
new ListViewItem.ListViewSubItem(lviAustralia,
"7,686,850");
lviAustralia.SubItems.Add(subAustralia);
subAustralia = new ListViewItem.ListViewSubItem(lviAustralia,
"19,731,984");
lviAustralia.SubItems.Add(subAustralia);
subAustralia = new ListViewItem.ListViewSubItem(lviAustralia,
"Canberra");
lviAustralia.SubItems.Add(subAustralia);
subAustralia = new ListViewItem.ListViewSubItem(lviAustralia,
"au");
lviAustralia.SubItems.Add(subAustralia);
lvwCountries.Items.Add(lviAustralia);
. . .

C# 3.0 Practical Learning II 700


 ForeColor: You can assign the desired color to
ListViewItem.ForeColor property to paint the item with a color of
your choice. This would be done as follows:
 
ListViewItem lviSweden = new ListViewItem("Sweden");
lviSweden.ForeColor = Color.Red;
ListViewItem.ListViewSubItem subSweden =
new ListViewItem.ListViewSubItem(lviSweden, "449,964");
lviSweden.SubItems.Add(subSweden);
subSweden = new ListViewItem.ListViewSubItem(lviSweden,
"8,878,085");
lviSweden.SubItems.Add(subSweden);
subSweden = new ListViewItem.ListViewSubItem(lviSweden,
"Stockholm");
lviSweden.SubItems.Add(subSweden);
subSweden = new ListViewItem.ListViewSubItem(lviSweden, "se");
lviSweden.SubItems.Add(subSweden);
lvwCountries.Items.Add(lviSweden);

 BackColor: The ListViewItem.BackColor property allows you to paint the


background of an item with a color of your choice. This would be done as
follows:
 
ListViewItem lviEgypt = lvwCountries.Items.Add("Egypt");
lviEgypt.BackColor = Color.Blue;
lviEgypt.SubItems.Add("1,001,450");
lviEgypt.SubItems.Add("74,718,797");
lviEgypt.SubItems.Add("Cairo");
lviEgypt.SubItems.Add("eg");

Practical Learning: Applying Aesthetic Effects

C# 3.0 Practical Learning II 701


1. To apply aesthetic effects, change the Click event of the New Property
button as follows:
 
private void btnNewProperty_Click(object sender, EventArgs e)
{
AvailableProperty dlgProperty = new AvailableProperty();

Random rndNumber = new Random(DateTime.Now.Millisecond);


int number1 = rndNumber.Next(100, 999);
int number2 = rndNumber.Next(100, 999);
string propNumber = number1 + "-" + number2;

dlgProperty.txtPropertyNumber.Text = propNumber;
dlgProperty.Text = "Altair Realtors - New Property";

if (dlgProperty.ShowDialog() == DialogResult.OK)
{
string strPropertyType =
dlgProperty.cbxPropertyTypes.Text;
string strAddress = dlgProperty.txtAddress.Text;
string strCity = dlgProperty.txtCity.Text;
string strState = dlgProperty.cbxStates.Text;
string strZIPCde = dlgProperty.txtZIPCode.Text;
string strBedrooms = dlgProperty.txtBedrooms.Text;
float Bathrooms =
float.Parse(dlgProperty.txtBathrooms.Text);
decimal MarketValue =
decimal.Parse(dlgProperty.txtMarketValue.Text);

ListViewItem lviProperty =
new
ListViewItem(dlgProperty.txtPropertyNumber.Text);

if (strPropertyType == "Single Family" )


{
lviProperty.BackColor = Color.Navy;
lviProperty.ForeColor = Color.LightBlue;
}
else if (strPropertyType == "Townhouse")
{
lviProperty.BackColor = Color.Brown;
lviProperty.ForeColor = Color.White;
}
else
{
lviProperty.BackColor = Color.DarkGreen;
lviProperty.ForeColor = Color.Lime;
}

lviProperty.SubItems.Add(strPropertyType);
lviProperty.SubItems.Add(strAddress);
lviProperty.SubItems.Add(strCity);
lviProperty.SubItems.Add(strState);
lviProperty.SubItems.Add(strZIPCde);

C# 3.0 Practical Learning II 702


lviProperty.SubItems.Add(strBedrooms);
lviProperty.SubItems.Add(Bathrooms.ToString("F"));
lviProperty.SubItems.Add(MarketValue.ToString("C"));
lvwProperties.Items.Add(lviProperty);
}
}

2. Execute the application and test the form by creating four different
records
 

3. Close the form and return to your programming environment

Locating a List View Item


The items of a list view are stores in a collection represented by the
ListView.Items property. To know the number of items in the list, you can
retrieve the value of the ListViewItemCollection.Count property. Each
member of this collection has an index represented by the
ListViewItemCollection.Index property.

You can also locate an item using the coordinates of a point inside its
bounding area. To use this technique, you can call the GetItemAt() method
of the ListView class. Its syntax is:
public ListViewItem GetItemAt(int x, int y);

This method expects the coordinates (x, y) of a point. If an item is found at


that point, this method returns it. If there is no item at that point, the method
returns 0.

Deleting Items

C# 3.0 Practical Learning II 703


To delete an item from a
list view, you can call the
ListViewItemCollection.Remove() method. Its syntax is:

public virtual void Remove(ListViewItem item);

This method takes as argument the ListViewItem object to be deleted. If


you are already positioned at that item, you can call its own
ListViewItem.Remove() method. Its syntax is:

public virtual void Remove();

To delete an item based on


its index, you can call the
ListViewItemCollection.RemoveAt() method whose syntax is:

public virtual void RemoveAt(int index);

When calling this method, you must pass the index of the undesired item. If
the item is found, it would be deleted. If you provide a negative index or one
that is higher than the ListViewItemCollection.Count property, the
compiler would throw an ArgumentOutOfRangeException exception.

To delete all items from a list view, you can call the ListViewItem.Clear()
method. Its syntax is:
public virtual void Clear();

When called, this method removes all items of the list view.

Characteristics of a List View


 

Column Header Style


If you create the columns of a list view, when the user displays the detail
view, the column headers appear and behave like regular buttons. This also
means that the user can click a column header and you can take action. If
you don't want this appearance and this behavior, you can make the columns
appear flat. This characteristics is controlled by the HeaderStyle property of
the ListView class. This property is based on the ColumnHeaderStyle
enumerator. Its members are:

 Clickable: This is the default style. The columns headers appear and behave like
buttons:
 

C# 3.0 Practical Learning II 704


lvwCountries.HeaderStyle = ColumnHeaderStyle.Clickable;

 Nonclickable: The columns are flat and don't change their appearance when the
user clicks one:
 
lvwCountries.HeaderStyle = ColumnHeaderStyle.Nonclickable;

 None: No column header appears:


 
lvwCountries.HeaderStyle = ColumnHeaderStyle.None;

Selecting Items in a List View


To select an item in the list, the user can click it. The selected item indicates
this by being highlighted. To select another item, the user can click it and this
automatically dismisses the previous selection. If you want, you can give the
user the ability to select more than one item or you can prevent the user from
selecting more than one item. This characteristic is controlled by the
MultiSelect property of the ListView class. Its default value is true, which
allows the user to select one or more items. If you set it to false, the user can
select only one item at a time.

C# 3.0 Practical Learning II 705


You can also allow the user to select an item by positioning the mouse over it.
This characteristic is controlled by the HoverSelection property of the
ListView class.

When an item has been selected or more than one item are selected, the
selected items are stored in a list represented by the SelectedItems
property of the ListView class. The ListView.SelectedItems property is
an object based on the ListView.SelectedListViewItemCollection
class. If the ListView.MultiSelect property is set to false, this collection
would contain only one item.

The number of items selected in the control is known as the Count property
of the SelectedListViewItemCollection class. Each item selected can be
identified through the Item indexed property of the
SelectedListViewItemCollection class.

The SelectedListViewItemCollection class holds a list of the objects that


are selected and each is identified as a ListViewItem. If you are more
interested in the positions of the items selected and not necessarily their
objects, you can use the SelectedIndices property of the ListView class.
Each item selected has its index stored in this list. The
ListView.SelectedIndices property is based on the
ListView.SelectedIndexCollection class.

After selecting an item, if the user clicks another control, the item that was
selected would not be highlighted anymore. If you want the control to
continue showing the current selection even when the list view loses focus,
set the value of the HideSelection Boolean property of the ListView class
accordingly.

Full Row Selection


By default, to select an item, the user must click the item itself and not one of
its sub-items. If you want an item and its sub-items to be selected when the
user clicks anything on their line, you can change the value of the
ListView.FullRowSelect Boolean property. Its default value is set to false,
which obliges the user to click the item itself. If you set this property to true,
the whole row would be highlighted when either you or the user selects it.

Practical Learning: Allowing Full Row Selection

1. On the form, click the list view

2. In the Properties window, double-click FullRowSelect property to set


its value to True

Grid Lines

C# 3.0 Practical Learning II 706


When using the detail view, to make a list view more indicative, you can
underline each row. This characteristic is controlled by the GridLines Boolean
property of the ListView class. The default value of this property is false. If you
set it to true, horizontal grid lines would appear among items throughout the list
view, including empty rows:

lvwCountries.GridLines = true;

Practical Learning: Writing Code For a Toolbar

1. Double-click GridLines to set its value to True

2. Execute the application and create the list of properties

3. Close the form

List Items and Check Boxes


Besides, or instead of, icons, you can display check boxes with the items of a
list view. This characteristic is controlled by the CheckBoxes property. Its
default value is false, which omits displaying the check boxes. If you set it to
true, a check box would appear on the left of each item of the list view:

lvwCountries.CheckBoxes = true;

C# 3.0 Practical Learning II 707


The Open Dialog Box
 

Description
Besides saving files, another common operation performed by users consists
of opening files. This refers to existing files since a file must primarily exist.
To support this operation, Microsoft Windows provides a standard object:
the Open File dialog box:

  

Open File Dialog Box Creation


To provide file opening support, the .NET Framework provides the
OpenFileDialog class which is derived from the FileDialog class that in
fact provides most of its functionality. The easiest way to use it is to click the
OpenFileDialog button from the Toolbox and click the form. You can click
anywhere on the form because the OpenFileDialog object would not be seen

C# 3.0 Practical Learning II 708


at run time. After placing it on the form, you can use the Properties window
to configure it.

If you prefer to dynamically create an Open dialog box, declare a variable of


type OpenFileDialog and use the new operator to allocate memory using its
default constructor. Here is an example:
using System;
using System.Windows.Forms;

public class Exercise : Form


{
private OpenFileDialog ofd;

public Exercise()
{
InitializeComponent();
}

void InitializeComponent()
{
ofd = new OpenFileDialog();
}
}

public class Program


{
public static int Main()
{

Application.Run(new Exercise());

return 0;
}
}

Characteristics of the Open Dialog


Box
 

The Filename
One of the most important properties of an Open dialog box is the file it
presents to the user. This is represented by the FileName property. If you
want a default file to be specified when the dialog box comes up, you can
specify this in the FileName property of the Properties window. If you need
to use this property, you should make sure the file can be found. If the file is

C# 3.0 Practical Learning II 709


located in the same folder as the application, you can provide just its name. If
the file is located somewhere else in the hard drive, you should provide its
complete path.

Most of the time, you will not be concerned with this property if you are
creating an application that will allow the users to open any files of their
choice. Once a file is located, it can be accessed using the
OpenFileDialog.FileName property.

The Filter
To make your application more effective, you should know what types of files
your application can open. This is taken care of by specifying a list of
extensions for the application. To control the types of files that your
application can open, specify their extensions using the Filter Property. The
Filter string is created exactly like that of a SaveFileDialog control as we
saw earlier.

The Filter Index


Like the SaveFileDialog control, the default extension is the one the dialog
box would first filter during file opening. If you want the Open dialog box to
easily recognize a default type of file when the dialog box opens, you can
specify the extension's type using the DefaultExt property. You can also use
the FilterIndex we saw earlier to indicate the default index of the Files of
Type combo box.

For convenience, or for security reasons, Open dialog boxes of


applications are sometimes asked to first look for files in a specific location
when the Open File dialog box comes up. This default folder is specified using
the InitialDirectory property.

Showing the Dialog Box


The essence of using the Open dialog box is to be able to open a file. This job
is handled by the ShowDialog() method. Here is an example:
public class Exercise : Form
{
private OpenFileDialog ofd;

public Exercise()
{
InitializeComponent();
}

void InitializeComponent()
{

C# 3.0 Practical Learning II 710


ofd = new OpenFileDialog();
ofd.ShowDialog();
}
}

After opening the dialog box, if the user selects a file and clicks OK or presses
Enter, the file would be opened.

Opening Various Files


Most of the time, users are interested in opening one file to view or
manipulate. It is also possible for a user to want to select various files and
open them at the same time. When the user clicks OK after using the Open
dialog box, before taking the next step, you may need to find out whether the
user selected various files. To get this information, you can check the value of
the OpenFileDialog.Multiselect Boolean property. If the user had
selected various files, this property produces a true result. If the user selected
only one file, this property renders a false result. The result of this checking
process allows you either to agree to open the files or to take some action of
your choice.

Opening a File As Read-Only


After a file has been opened, the user may want to alter it. For example, if it
is a text document, the user may want to add and/or delete some words. In
some cases, you may want the user to be able to open a file but not to be
able to modify it. To provide this restriction, you can set the document as
read-only. In some other cases, you may want to let the user decide on this.
If you want to give this option to the user, you can start by displaying a read-
only check box on the dialog box. To support this, the OpenFileDialog
class is equipped with the ShowReadOnly property. If you set it to true, the
dialog box would be equipped with an Open As Read-Only check box in its
lower section:

C# 3.0 Practical Learning II 711


By default, the Open As Read-Only check box is cleared when the dialog box
comes up. The user has the option of keeping it that way or checking it when
opening a file. The OpenFileDialog class provides the ReadOnlyChecked
property to accompany the read-only option. If you want to display a check
mark in the Open As Read-Only check box, you can set the
ReadOnlyChecked property to true. On the other hand, when the user selects
a file to open, you can check the value of the ReadOnlyChecked property. If
it is true, this indicates that the user had clicked the Open As Read-Only
check box.

Print Preview
 

Introduction
If you use the printing process that solely involves the print dialog box, you
may send a document to the printer without knowing what the printed

C# 3.0 Practical Learning II 712


document would look like on the piece of paper. In the same way, the user
would have to simply accept the way you designed the printed document to
appear. One way you can assist the user consists of displaying a preview of
what the printed sheet would look like. This is the idea behind the concept of
print preview.

Print preview consists of displaying, on the computer monitor, a sample


representation of what the document would look like once printed.

Providing Print Preview


Print preview is primarily a technique of drawing a sample printed sheet on a
form. It is implemented by the PrintPreviewDialog button from the
Toolbox. Therefore, at design time, to provide print preview, from the Printing
section of the Toolbox and click the form. As its name indicates, the dialog
box is already created but like the other dialog boxes of the .NET Framework,
you must add it to a form in order to make it available in your application.

In the .NET Framework, print preview is implemented through the


PrintPreviewDialog class. This class is derived from the Form class. Based
on this, to programmatically create a print preview, you can start by declaring
a variable of type PrintPreviewDialog. Here is an example:
using System;
using System.Drawing;
using System.Windows.Forms;

public class Exercise : Form


{
Button btnPrintPreview;

public Exercise()
{
InitializeComponent();
}

void InitializeComponent()
{
btnPrintPreview = new Button();
btnPrintPreview.Location = new Point(12, 12);
btnPrintPreview.Text = "&Print Preview...";
btnPrintPreview.Width = 100;
btnPrintPreview.Click += new
EventHandler(PreviewDocumentClick);

Controls.Add(btnPrintPreview);
}

void PreviewDocumentClick(object sender, EventArgs e)


{

C# 3.0 Practical Learning II 713


PrintPreviewDialog dlgPrint = new PrintPreviewDialog();
}
}

public class Program


{
static int Main()
{
System.Windows.Forms.Application.Run(new Exercise());
return 0;
}
}

As a dialog-based
object, to display the print preview, the
PrintPreviewDialog class inherits the ShowDialog() method from its
parent the Form class. Here is an example:
void PreviewDocumentClick(object sender, EventArgs e)
{
PrintPreviewDialog dlgPrintPreview = new
PrintPreviewDialog();

dlgPrintPreview.ShowDialog();
}

This would produce:

Characteristics of the Print Preview


 

C# 3.0 Practical Learning II 714


The Preview Area
The Print Preview window appears as a finished designed form with a toolbar,
a preview area, and two scroll bars.

The preview area shows a sample of what a printed sheet would look like. If
the dialog box is not "aware" of what would be printed, it displays the
"Document does not contain any pages" string. This means that, in order to
display something, you must create and design it. To make this possible, the
PrintPreviewDialog class is equipped with a property named Document.
The PrintPreviewDialog.Document property is of type PrintDocument.
Therefore, in order to design a sample sheet, you should have created and
configured a PrintDocument object. Here is an example:

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

public class Exercise : Form


{
Button btnPrintPreview;
PrintPreviewDialog dlgPrintPreview;
PrintDocument docPrint;

public Exercise()
{
InitializeComponent();
}

void InitializeComponent()
{
btnPrintPreview = new Button();
btnPrintPreview.Location = new Point(12, 12);
btnPrintPreview.Text = "&Print Preview...";
btnPrintPreview.Width = 100;
btnPrintPreview.Click += new
EventHandler(PreviewDocumentClick);

Controls.Add(btnPrintPreview);

dlgPrintPreview = new PrintPreviewDialog();


docPrint = new PrintDocument();

dlgPrintPreview.Document = docPrint;
}

void PreviewDocumentClick(object sender, EventArgs e)


{
dlgPrintPreview.ShowDialog();
}
}

C# 3.0 Practical Learning II 715


public class Program
{
static int Main()
{

System.Windows.Forms.Application.Run(new Exercise());

return 0;
}
}

This would produce:

As you can see, simply assigning a PrintDocument object to a print preview


form only creates a blank sheet. In order to show a preview, you must design
it. To make this possible, the PrintDocument class

To assist you with actually designing what you want to display in the preview
area, the PrintDocument class fires an event named PrintPage. This event
is of type PrintPageEventArgs. The PrintPageEventArgs class is equipped
with a property named Graphics, which is of type Graphics. You can then
use your knowledge of the Graphics class to create or design the preview.
Here is an example:
using System;
using System.Drawing;
using System.Windows.Forms;
using System.Drawing.Printing;

public class Exercise : Form


{
Button btnPrintPreview;
PrintPreviewDialog dlgPrintPreview;

C# 3.0 Practical Learning II 716


PrintDocument docPrint;

public Exercise()
{
InitializeComponent();
}

void InitializeComponent()
{
btnPrintPreview = new Button();
btnPrintPreview.Location = new Point(12, 12);
btnPrintPreview.Text = "&Print Preview...";
btnPrintPreview.Width = 100;
btnPrintPreview.Click += new
EventHandler(PreviewDocumentClick);

Controls.Add(btnPrintPreview);

dlgPrintPreview = new PrintPreviewDialog();


docPrint = new PrintDocument();
docPrint.PrintPage += new
PrintPageEventHandler(docPrintPage);

dlgPrintPreview.Document = docPrint;
}

void PreviewDocumentClick(object sender, EventArgs e)


{
dlgPrintPreview.ShowDialog();
}

void docPrintPage(object sender, PrintPageEventArgs e)


{
Image imgPerson =
Image.FromFile(@"E:\Programs\persons1.gif");
e.Graphics.DrawImage(imgPerson, 10, 10);
}
}

On our computer, this produced:

C# 3.0 Practical Learning II 717


Printing From the Print Preview
To print the contents of the preview area, the user can click the Print button
from the toolbar. Two things would happen. The compiler would select
the default printer and the document would be sent directly to that printer.
This means that, first there should be a (known) default printer and the user
should know what that printer is; second, the user would not be able to
change the printer if more than one is available. If you want the user to be
able to select the printer, you should provide a Print dialog box that the user
can probably access from a menu of the application.

Zooming the Preview


By default, when the print preview window appears to the user, it assumes
some default dimensions that may make it small. Because it is derived from
the Form class, you can maximize it if you want. Here is an example:
void PreviewDocumentClick(object sender, EventArgs e)
{
dlgPrintPreview.WindowState = FormWindowState.Maximized;
dlgPrintPreview.ShowDialog();
}

If the print preview is not maximized, the content of the preview area may
appear (too) small for the user, especially if it is made of text. To enlarge it,
the user has two alternatives. If the user maximizes the window, the preview
area would also be enlarged and the content would be easier to see. As an
alternative, the user can click the arrow of the Zoom button. This would
display a list of the zoom rates:

C# 3.0 Practical Learning II 718


The user can then click one of the values.

A Document of Various Pages


So far, we were assuming that the user was printing a one-page document.
With some files, the document may span more than one page. By default,
when the print preview comes up, the preview are would display only one
page. The user has the choice of displaying two or more pages at a time,
even to specify some arrangement of these pages. To support this, the
toolbar of the print preview is equipped with various buttons labeled One
Page, Two Pages, Three Pages, Four Pages, and Six Pages.

After using the print preview, the user can close it.

Windows Control: Scroll Bars


 

Description
A scrollbar is a control that allows the user to navigate a document in two
directions by clicking a button that displays an arrow. The control is equipped

C# 3.0 Practical Learning II 719


with one button at each of its ends. Between the buttons, there is a (long)
bar and on the bar, there is sliding object called a thumb:

To use a scroll bar, the user can click one of the arrows. This causes the
thumb to move towards the button that was clicked. The user can also click
and hold the mouse on a button. This causes the thumb to move
continuously, as long as the button is held down, towards the button, until
the thumb cannot move any farther. The user can also drag the thumb in one
direction to move it or click between a button and the thumb. This causes the
thumb to move faster than clicking a button. The thumb of a scroll bar can be
positioned only along the scroll bar, between the scroll bar’s button.

Based on their orientation, there are two types of scroll bars: horizontal and
vertical. The horizontal scroll bar allows the user to navigate a document left
and right. The vertical scroll bar allows navigating up and down.

Based on their relationship with the parent control or owner, there are two
types of scroll bars: those that are (automatically) associated with their
parent or owner and scroll bar controls that are manually added by the
programmer.

Automatically-Added Scroll Bars


To effectively implement their functionality, some controls must be equipped
with one or two scroll bars. As we will see with list-based controls such as list
boxes, combo boxes, tree views, list views, etc, when the items of their list
exceed the allocated client area of the control, the list should display a scroll
bar to give access to the hidden part of their list. This type of automatically
added scroll bar is usually positioned on the right side of the control for most
Latin-based languages including US English.

The Palette property page of Borland C++ Builder’s Environment Options dialog
box shows the Pages list box and the Components list view. Because each
control has a long list that it cannot show completely, it is equipped with a
vertical scroll bar. This allows the user to display the hidden list when needed.

C# 3.0 Practical Learning II 720


These types of scroll bars are automatically added by the operating system to
the control that needs it, unless the programmer explicitly prevented their
showing.

Scroll Bars Upon Request


Some controls are ready to display a scroll bar upon request, that is, if you
want them to. Such controls are the form, the text box, the rich text box,
and the panel. When designing one of these controls, you can ask it to
display or hide either or both scroll bars as you see fit.

Although they are the most used containers, by default, the form and the
panel control don't display scroll bars, even if you add controls that exceed
their allocated client area:

C# 3.0 Practical Learning II 721


If you have controls that exceed the client area of a form or a panel and if
you want them to display scroll bars so the user can navigate to the hidden
parts of the container, change the value of the form or the panel's
AutoScroll Boolean property. By default, this property is set to False. If you
set its value to true, the control container would be equipped with one or
both of the scroll bars as necessary:

The text box and the rich text box controls are equipped with a property
called ScrollBars.

Text-Based Applications and Scroll Bars


 

Because they are always likely to display a long text, the multi-line text box
and the rich text box controls are natively ready to display either or both
scroll bars. This is easily done using the ScrollBars property. It provides four
options as follows:

Value Comments

None No scroll bar will be displayed

C# 3.0 Practical Learning II 722


This is the default value

A horizontal scroll bar will display at the bottom of


Horizontal
the control or document

A vertical scroll bar will display on the right side of


Vertical
the control or document

A horizontal scroll bar will display at the bottom of


Both  the control and a vertical scroll bar will display on
the right side of the control or document

Thanks to rapid application development (RAD) and object-oriented


programming (OOP), you do not have to permanently set the scroll bar(s).
You can act in response to the user doing something and decide when to
display or hide either or both scroll bars.

The Scroll Bar Control

Introduction
Microsoft Windows provides two other types of scroll bars, considered
complete controls in their own right. Like all other controls, these ones must
be explicitly created; that is, they are not added automatically but they
provide most of the same basic functionality as if the operating system's
automatically added the scroll bars.

Creating a Scroll Bar Control


To create a scroll bar control, on the Toolbox, you can click either the
VScrollBar or the HScrollBar button then click a container. The scroll bar is
one of the earliest controls of the Microsoft Windows operating system. Each
control is implemented through a class of the same name. The VScrollBar
and the HScrollBar classes are based on the ScrollBar class that
essentially provides all of their functionalities.

Characteristics of a Scroll Bar

C# 3.0 Practical Learning II 723


The Minimum and Maximum
When using a scroll bar, the user can navigate from one end of the control to
the other end. These are the control’s minimum and maximum values
represented respectively by the Minimum and the Maximum properties. For a
horizontal scrollbar, the minimum is the far left position that the bar can
assume. For a vertical scrollbar, this would be the most top position:

As you can see from this illustration, the minimum value of a vertical scroll bar
is on top. This is the way the vertical scroll bar control of the .NET Framework
is configured. On a regular application, the minimum of a vertical scroll is in the
bottom section of the control.

The maximum would be the opposite. By default, a newly added scrollbar


allows scrolling from 0 to 100. To change these values at design time, type a
natural number for each field in the Properties window.

The Value of a Scroll Bar


The primary technique the user applies to a scrollbar is to click one of the
arrows at the ends of the control. As the bar slides inside of the control, it
assumes an integer position from Minimum to Maximum. At one time, the
position that the bar has is the Value property. At design time, you can use
the Value property to set the position that the scrollbar would assume when
the form opens. If you set the Value to a value less than the Minimum, you
would receive an error of Invalid Property Value:

C# 3.0 Practical Learning II 724


In the same way, if you set the value of Value to a value higher than the
Maximum, you would receive an Invalid Property Value error. To
programmatically set the position of the bar, assign the desired value, which
must be between Minimum and Maximum, to the Value property.

At run time, when the user scrolls the control, you can find the position of the
bar by getting the value of the Value property.

The Small Change


When the user clicks an arrow of a scrollbar, the bar slides by one unit. This
unit is represented by the SmallChange property and is set to 1 by default. If
you want the bar to slide more than one unit, change the value of the
SmallChange property to a natural number between Minimum and Maximum.
The higher the value, the faster the sliding would occur because the bar
would jump by SmallChange units.

The Large Change


There are two main ways the user can scroll faster using scrollbars: by
pressing either page buttons or by clicking the scrolling region. The amount
covered using this technique is controlled by the LargeChange property.
Once again, the user can scroll only between Minimum and Maximum. To find
the scrolling amount, the compiler would divide the actual scrolling range
(the difference between Maximum and Minimum) by the LargeChange value.
When the user clicks in the scrolling region or presses the Page Up or Page
Down keys, the bar would jump by LargeChange up to the scrolling amount
value. You can also change the LargeChange property programmatically.

Windows Control: The Scroll Bars


 

The Scroll Bar Control

C# 3.0 Practical Learning II 725


 

Introduction
Microsoft Windows provides two other types of scroll bars, considered
complete controls in their own right. Like all other controls, these ones must
be explicitly created; that is, they are not added automatically but they
provide most of the same basic functionality as if the operating system's
automatically added the scroll bars.

Creating a Scroll Bar Control


To create a scroll bar control, on the Toolbox, you can click either the
VScrollBar or the HScrollBar button then click a container. The scroll bar is
one of the earliest controls of the Microsoft Windows operating system. Each
control is implemented through a class of the same name. The VScrollBar
and the HScrollBar classes are based on the ScrollBar class that
essentially provides all of their functionalities.

Characteristics of a Scroll Bar

The Minimum and Maximum


When using a scroll bar, the user can navigate from one end of the control to
the other end. These are the control’s minimum and maximum values
represented respectively by the Minimum and the Maximum properties. For a
horizontal scrollbar, the minimum is the far left position that the bar can
assume. For a vertical scrollbar, this would be the most top position:

C# 3.0 Practical Learning II 726


As you can see from this illustration, the minimum value of a vertical
scroll bar is on top. This is the way the vertical scroll bar control of
the .NET Framework is configured. On a regular application, the
minimum of a vertical scroll is in the bottom section of the control.
The maximum would be the opposite. By default, a newly added scrollbar allows
scrolling from 0 to 100. To change these values at design time, type a natural
number for each field in the Properties window.

The Value of a Scroll Bar


The primary technique the user applies to a scrollbar is to click one of the
arrows at the ends of the control. As the bar slides inside of the control, it
assumes an integer position from Minimum to Maximum. At one time, the
position that the bar has is the Value property. At design time, you can use
the Value property to set the position that the scrollbar would assume when
the form opens. If you set the Value to a value less than the Minimum, you
would receive an error of Invalid Property Value:

In the same way, if you set the value of Value to a value higher than the
Maximum, you would receive an Invalid Property Value error. To
programmatically set the position of the bar, assign the desired value, which
must be between Minimum and Maximum, to the Value property.

At run time, when the user scrolls the control, you can find the position of the
bar by getting the value of the Value property.

The Small Change


When the user clicks an arrow of a scrollbar, the bar slides by one unit. This
unit is represented by the SmallChange property and is set to 1 by default. If
you want the bar to slide more than one unit, change the value of the
SmallChange property to a natural number between Minimum and Maximum.
The higher the value, the faster the sliding would occur because the bar
would jump by SmallChange units.

The Large Change

C# 3.0 Practical Learning II 727


There are two main ways the user can scroll faster using scrollbars: by
pressing either page buttons or by clicking the scrolling region. The amount
covered using this technique is controlled by the LargeChange property.
Once again, the user can scroll only between Minimum and Maximum. To find
the scrolling amount, the compiler would divide the actual scrolling range
(the difference between Maximum and Minimum) by the LargeChange value.
When the user clicks in the scrolling region or presses the Page Up or Page
Down keys, the bar would jump by LargeChange up to the scrolling amount
value. You can also change the LargeChange property programmatically.

Windows Control: The Tick Counter


 

Introduction
The Environment class provides a special property used to count a specific
number of lapses that have occurred since you started your computer. This
information or counter is available through the TickCount property. This
property counts the number of milliseconds that have elapsed since you
started your computer. Just like the timer control, what you do with the result
of this property is up to you and it can be used in various circumstances.

After retrieving the value that the Environment.TickCount property, you


can display it in a text-based control. Here is an example:
private void Form1_Load(object sender, System.EventArgs e)
{
this.textBox1.Text = Environment.TickCount.ToString();
}

Practical Learning: Counting the Computer's Ticks

1. Start a new Windows Application named CompAppElapsedTime1

C# 3.0 Practical Learning II 728


2. Design the form as follows:
 

3. From the Components section of the Toolbox, click the Timer control
and click the form

4. Change the timer's properties as follows:


Interval:20
Enabled: True

5. Double-click an unoccupied area of the form to generate its Load event

6. Declare a global private integer named CompTime and initialize it in the


Load event as follows:
 
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace CompAppElapsedTime1
{
public partial class Form1 : Form
{
private int CompTime;

public Form1()
{
InitializeComponent();
}

private void Form1_Load(object sender, EventArgs e)


{
CompTime = Environment.TickCount;
}
}
}

C# 3.0 Practical Learning II 729


7. Return to the form

8. Double-click the timer1 control and implement its Timer event as follows:
 
private void timer1_Tick(object sender, EventArgs e)
{
int CurTickValue = Environment.TickCount;
int Difference = CurTickValue - CompTime;

label1.Text = string.Format("This computer has been ON for


{0}",
CurTickValue.ToString());
label2.Text = string.Format("This application has been
running for {0}",
Difference.ToString());
}

9. Return to the form and double-click the Close button

10. Implement the event as follows:


 
private void btnClose_Click(object sender, EventArgs e)
{
Close();
}

11. Test the application


 

12. After testing the application, close it

13. To make the values easier to read, change the code of the OnTimer
event as follows:
 
private void timer1_Tick(object sender, EventArgs e)
{
int curTickValue = Environment.TickCount;
int difference = curTickValue - CompTime;

int computerHours, computerMinutes, computerSeconds;

C# 3.0 Practical Learning II 730


int applicationHours, applicationMinutes,
applicationSeconds;

computerHours = (curTickValue / (3600 * 999)) % 24;


computerMinutes = (curTickValue / (60 * 999)) % 60;
computerSeconds = (curTickValue / 999) % 60;

applicationHours = (difference / (3600 * 999)) % 24;


applicationMinutes = (difference / (60 * 999)) % 60;
applicationSeconds = (difference / 999) % 60;

label1.Text = string.Format("This computer has been ON for


{0} " +
"hours, {1} minutes {2} seconds",
computerHours.ToString(),
computerMinutes.ToString(),
computerSeconds.ToString());

label2.Text = string.Format("This application has been


running " +
"for {0} hours, {1} minutes {2}
seconds",
applicationHours.ToString(),
applicationMinutes.ToString(),
applicationSeconds.ToString());
}

14. Execute the application to test it:


 

15. After testing the application, close the form

Windows Control: Checked List


Boxes

C# 3.0 Practical Learning II 731


 

Description
A checked list box is a list box whose items are each equipped with a check
box. In the following Customize dialog box of Microsoft Office, the control
under the Toolbars label is a checked list box:

A checked list box combines the functionalities of the list box and the check
box controls. As a list box, it displays each of its items on a line. If there are
too many items than the control can display, it would be equipped with a
vertical scroll bar.

To select an item in the list, the user can click the desired string. The most
important and obvious characteristic of the checked list box is that each item
displays a check box on its left. This box allows the user to select or deselect
each item. To select an item, the user must click its box and not its string, to
indicate an explicit selection. This draws a check mark in the box. As
described with the check box control, the user can deselect an item by
removing the check mark. The check mark indicates that an item is selected
and the absence of the check mark indicates the contrary. Like the check box
control, you can allow the user to indicate a "half-checked" item. In this case,
a check box can appear unchecked, checked, or grayed.

Practical Learning: Introducing Checked List Boxes

C# 3.0 Practical Learning II 732


1. Start a new Windows Application named AltairRealtors1

2. On the main menu, click Project ->Add Class...

3. Set the Name to AvailableProperty and click Add

4. Change the file as follows:


 
using System;

namespace AltairRealtors1
{
public class AvailableProperty
{
long propNbr;
string propType;
string adrs;
string ct;
string stt;
int zip;
short beds;
float baths;
double mValue;

public long PropertyNumber


{
get { return propNbr; }
set { propNbr = value; }
}

public string PropertyType


{
get { return propType; }
set { propType = value; }
}

public string Address


{
get { return adrs; }
set { adrs = value; }
}

public string City


{
get { return ct; }
set { ct = value; }
}

public string State


{
get { return stt; }
set { stt = value; }
}

public int ZIPCode

C# 3.0 Practical Learning II 733


{
get { return zip; }
set { zip = value; }
}

public short Bedrooms


{
get { return beds; }
set { beds = value; }
}

public float Bathrooms


{
get { return baths; }
set { baths = value; }
}

public double MarketValue


{
get { return mValue; }
set { mValue = value; }
}

public AvailableProperty()
{
}

public AvailableProperty(long code, string type,


string address, string city,
string state, int zCode,
short bedroom, float bathroom,
double value)
{
propNbr = code ;
propType = type ;
adrs = address ;
ct = city ;
stt = state ;
zip = zCode ;
beds = bedroom ;
baths = bathroom ;
mValue = value;
}
}
}

5. In the Solution Explorer, right-click Form1.cs and click Rename

6. Type RealEstate.cs and press Enter twice

Creating a Checked List Box


To support checked list boxes, the .NET Framework provides the
CheckedListBox class. At design time, to add a checked list box to your
application, from the Common Controls section of the Toolbox, click the

C# 3.0 Practical Learning II 734


CheckedListBox button and click the form or the container that would host
the control. To programmatically create a checked list box, declare a variable
of type CheckedListBox, use the new operator to allocate memory for it, and
add it to the Controls collection of its parent. Here is an example:
using System;
using System.Drawing;
using System.Windows.Forms;

public class Exercise : System.Windows.Forms.Form


{
CheckedListBox lbxPersonalRelationships;

public Exercise()
{
InitializeComponent();
}

private void InitializeComponent()


{
lbxPersonalRelationships = new CheckedListBox();
lbxPersonalRelationships.Location = new Point(12, 12);

Controls.Add(lbxPersonalRelationships);
}
}

public class Program


{
static int Main()
{
System.Windows.Forms.Application.Run(new Exercise());
return 0;
}
}

This would produce:

Practical Learning: Creating Checked List Boxes

1. Design the form as follows:


 

C# 3.0 Practical Learning II 735


 

Other
Control Text Name
Properties

BorderStyle:
FixedSingle
Font: Times
Label Altair Realtors  
New Roman,
21.75pt,
style=Bold

Label Types to Show    

CheckedListBox   lbxPropertiesTypes  

Button Show btnShow  

C# 3.0 Practical Learning II 736


Font:
Garamond,
Label Properties_______  
15.75pt,
style=Bold

Label Prop #    

Label Address    

Label City    

Label State    

Label ZIP Code    

Label Beds    

Label Baths    

Label Market Value    

lbxPropertyNumber
ListBox    
s

ListBox   lbxAddresses  

ListBox   lbxCities  

ListBox   lbxStates  

ListBox   lbxZIPCodes  

C# 3.0 Practical Learning II 737


ListBox   lbxBedrooms  

ListBox   lbxBathrooms  

ListBox   lbxMarketValues  

Button Close btnClose  

2. Save the form

Characteristics of a Checked List


Box
 

Introduction
The CheckedListBox class is derived from the ListBox class. This means
that the checked list box possesses all the public (and protected)
characteristics of the list box and its parent the ListControl class. This
control also uses the HorizontalScrollbar and the HorizontalExtent
properties that behave exactly as we reviewed for the list box. It also uses
the SelectionMode property with the same behavior as that of the list box.

Creating the List of Items


As seen for the list box, the primary aspect of a checked list box is its list of
items. At design time, to create the list of items of a checked list box, access
its Properties window, and click the ellipsis button to open the String
Collection Editor. Type each item followed by a carriage return. After creating
the list, click OK. To programmatically create the list of items, access the
Items property. The list is created from the nested ObjectCollection class
that implements the IList, the ICollection, and the IEnumerable
interfaces. This means that the CheckedListBox.ObjectCollection class

C# 3.0 Practical Learning II 738


behaves the same as the ListBox.ObjectCollection class. Here is an
example:
public class Exercise : System.Windows.Forms.Form
{
CheckedListBox lbxPersonalRelationships;

public Exercise()
{
InitializeComponent();
}

private void InitializeComponent()


{
lbxPersonalRelationships = new CheckedListBox();
lbxPersonalRelationships.Location = new Point(12, 12);

lbxPersonalRelationships.Items.Add("Family Member");
lbxPersonalRelationships.Items.Add("Friend");
lbxPersonalRelationships.Items.Add("Classmate");
lbxPersonalRelationships.Items.Add("Business Partner");
lbxPersonalRelationships.Items.Add("Simple
Acquaintance");
lbxPersonalRelationships.Items.Add("Undefined");

Controls.Add(lbxPersonalRelationships);
}
}

This would produce:

Remember that you can also add an array of items by calling the AddRange()
and you can insert an item using the Insert() method.

Practical Learning: Creating a List of Items

1. On the form, click the checked list box

2. In the Properties window, click Items and click its ellipsis button

3. In the String Collection Editor, type Single Families and press Enter

4. Type Townhouses and press Enter

C# 3.0 Practical Learning II 739


5. Type Condominiums and press Enter

6. Type Trailers and click OK

Checking an Item
As mentioned already, the main difference between a list box and a checked
list is the presence of check marks in the former. When using the control, the
user can click one or more check boxes. Here is an example:

After the user has clicked a few check boxes, you may want to find out which
ones are checked. The checked list box provides two techniques you can use.

As seen for the list box, each item of the control has an index. When one, a
few, or all items have been checked (those that display a check mark), the
indices of the checked items are stored in a collection represented by the
CheckedIndices property. This property is based on the nested
CheckedIndexCollection collection class. The CheckedIndexCollection
class implements the IList, the ICollection, and the IEnumerable
interfaces.

The identifications of the checked items are stored in a collection represented


by the CheckedItems property. This property is based on the nested
CheckedItemCollection class. The CheckedItemCollection class
implements the IList, the ICollection, and the IEnumerable interfaces.
This implies that you can use it to get the number of selected items.

When the user has clicked item to put a check mark on it, the control fires the
ItemCheck event. Its formula is:

private void lbxPropertiesTypes_ItemCheck(object sender,


ItemCheckEventArgs e)
{

As you can see, the event is carried by the ItemCheckEventArgs class.

One of the most important operations to perform on a list of selected items is


to find out whether a particular item is checked. To get this information, the
CheckedItemCollection class provides a method named Contains. Its
syntax is:

C# 3.0 Practical Learning II 740


public bool Contains(object item);

This method takes as argument a value that can identify an item from the
checked list box. If the item is found and it is checked, this method returns
true. Otherwise, it returns false. 

Practical Learning: Using the List of Checked Items

1. Double-click an unoccupied area of the form to generate its Load event

2. Change the file as follows:


 
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace AltairRealtors1
{
public partial class RealEstate : Form
{
AvailableProperty[] properties = new
AvailableProperty[15];

public RealEstate()
{
InitializeComponent();
}

private void RealEstate_Load(object sender, EventArgs e)


{
properties[0] = new AvailableProperty();
properties[0].PropertyNumber = 602138;
properties[0].PropertyType = "Single Family";
properties[0].Address = "11604 Aldora Avenue";
properties[0].City = "Baltimore";
properties[0].State = "MD";
properties[0].ZIPCode = 21205;
properties[0].Bedrooms = 5;
properties[0].Bathrooms = 3.5F;
properties[0].MarketValue = 265880;

properties[1] = new AvailableProperty();


properties[1].PropertyNumber = 749562;
properties[1].PropertyType = "Townhouse";
properties[1].Address = "495 Parker House Terrace";
properties[1].City = "Gettysburg";
properties[1].State = "WV";
properties[1].ZIPCode = 26201;
properties[1].Bedrooms = 3;

C# 3.0 Practical Learning II 741


properties[1].Bathrooms = 2.5F;
properties[1].MarketValue = 225500;

properties[2] = new AvailableProperty();


properties[2].PropertyNumber = 304750;
properties[2].PropertyType = "Condominium";
properties[2].Address = "5900 24th Street NW #812";
properties[2].City = "Washington";
properties[2].State = "DC";
properties[2].ZIPCode = 20008;
properties[2].Bedrooms = 1;
properties[2].Bathrooms = 1.0F;
properties[2].MarketValue = 388665;

properties[3] = new AvailableProperty();


properties[3].PropertyNumber = 682630;
properties[3].PropertyType = "Single Family";
properties[3].Address = "6114 Costinna Avenue";
properties[3].City = "Martinsburg";
properties[3].State = "WV";
properties[3].ZIPCode = 25401;
properties[3].Bedrooms = 4;
properties[3].Bathrooms = 3.5F;
properties[3].MarketValue = 325000;

properties[4] = new AvailableProperty();


properties[4].PropertyNumber = 480750;
properties[4].PropertyType = "Condominium";
properties[4].Address = "10710 Desprello Street
#10D";
properties[4].City = "Rockville";
properties[4].State = "MD";
properties[4].ZIPCode = 20856;
properties[4].Bedrooms = 1;
properties[4].Bathrooms = 1.0F;
properties[4].MarketValue = 528445;

properties[5] = new AvailableProperty();


properties[5].PropertyNumber = 209475;
properties[5].PropertyType = "Single Family";
properties[5].Address = "519D Estuardo Way";
properties[5].City = "Silver Spring";
properties[5].State = "MD";
properties[5].ZIPCode = 20906;
properties[5].Bedrooms = 2;
properties[5].Bathrooms = 1.0F;
properties[5].MarketValue = 325995;

properties[6] = new AvailableProperty();


properties[6].PropertyNumber = 304185;
properties[6].PropertyType = "Townhouse";
properties[6].Address = "10116 Lottsford Drive";
properties[6].City = "Takoma Park";
properties[6].State = "MD";
properties[6].ZIPCode = 20910;
properties[6].Bedrooms = 4;

C# 3.0 Practical Learning II 742


properties[6].Bathrooms = 3.5F;
properties[6].MarketValue = 450500;

properties[7] = new AvailableProperty();


properties[7].PropertyNumber = 93857;
properties[7].PropertyType = "Single Family";
properties[7].Address = "9047 Woodyard Road";
properties[7].City = "York";
properties[7].State = "PA";
properties[7].ZIPCode = 17405;
properties[7].Bedrooms = 4;
properties[7].Bathrooms = 2.5F;
properties[7].MarketValue = 326885;

properties[8] = new AvailableProperty();


properties[8].PropertyNumber = 930755;
properties[8].PropertyType = "Condominium";
properties[8].Address = "3842 Accolade Avenue
#1206";
properties[8].City = "Alexandria";
properties[8].State = "VA";
properties[8].ZIPCode = 22231;
properties[8].Bedrooms = 3;
properties[8].Bathrooms = 2.0F;
properties[8].MarketValue = 525885;

properties[9] = new AvailableProperty();


properties[9].PropertyNumber = 240875;
properties[9].PropertyType = "Townhouse";
properties[9].Address = "842 Hempton Street";
properties[9].City = "Charlestown";
properties[9].State = "WV";
properties[9].ZIPCode = 25414;
properties[9].Bedrooms = 3;
properties[9].Bathrooms = 2.5F;
properties[9].MarketValue = 212500;

properties[10] = new AvailableProperty();


properties[10].PropertyNumber = 940075;
properties[10].PropertyType = "Single Family";
properties[10].Address = "4813 Woodland Court";
properties[10].City = "Falls Church";
properties[10].State = "VA";
properties[10].ZIPCode = 22042;
properties[10].Bedrooms = 5;
properties[10].Bathrooms = 3.5F;
properties[10].MarketValue = 645860;

properties[11] = new AvailableProperty();


properties[11].PropertyNumber = 931475;
properties[11].PropertyType = "Townhouse";
properties[11].Address = "5030 Goodson Road";
properties[11].City = "Arlington";
properties[11].State = "VA";
properties[11].ZIPCode = 22203;
properties[11].Bedrooms = 4;

C# 3.0 Practical Learning II 743


properties[11].Bathrooms = 3.5F;
properties[11].MarketValue = 435775;

properties[12] = new AvailableProperty();


properties[12].PropertyNumber = 248095;
properties[12].PropertyType = "Condominium";
properties[12].Address = "9182 Weston Ave NW #F14";
properties[12].City = "Washington";
properties[12].State = "DC";
properties[12].ZIPCode = 20016;
properties[12].Bedrooms = 2;
properties[12].Bathrooms = 1.0F;
properties[12].MarketValue = 425665;

properties[13] = new AvailableProperty();


properties[13].PropertyNumber = 293705;
properties[13].PropertyType = "Single Family";
properties[13].Address = "12404 Livingston
Boulevard";
properties[13].City = "Martinsburg";
properties[13].State = "WV";
properties[13].ZIPCode = 25401;
properties[13].Bedrooms = 4;
properties[13].Bathrooms = 2.50F;
properties[13].MarketValue = 225660;

properties[14] = new AvailableProperty();


properties[14].PropertyNumber = 937905;
properties[14].PropertyType = "Condominium";
properties[14].Address = "2039 Gonnard Road E5";
properties[14].City = "Laurel";
properties[14].State = "MD";
properties[14].ZIPCode = 20747;
properties[14].Bedrooms = 2;
properties[14].Bathrooms = 2;
properties[14].MarketValue = 275880;
}
}
}

3. Return to the form

4. On the form, double-click the Show button and implement its Click event
as follows:
 
private void btnShow_Click(object sender, EventArgs e)
{
lbxPropertyNumbers.Items.Clear();
lbxAddresses.Items.Clear();
lbxCities.Items.Clear();
lbxStates.Items.Clear();
lbxZIPCodes.Items.Clear();
lbxBedrooms.Items.Clear();
lbxBathrooms.Items.Clear();
lbxMarketValues.Items.Clear();

C# 3.0 Practical Learning II 744


if (lbxPropertiesTypes.CheckedItems.Contains("Single
Families"))
{
foreach (AvailableProperty prop in properties)
{
if (prop.PropertyType == "Single Family")
{

lbxPropertyNumbers.Items.Add(prop.PropertyNumber.ToString());
lbxAddresses.Items.Add(prop.Address);
lbxCities.Items.Add(prop.City);
lbxStates.Items.Add(prop.State);
lbxZIPCodes.Items.Add(prop.ZIPCode);
lbxBedrooms.Items.Add(prop.Bedrooms);
lbxBathrooms.Items.Add(prop.Bathrooms);
lbxMarketValues.Items.Add(prop.MarketValue);
}
}
}

if (lbxPropertiesTypes.CheckedItems.Contains("Townhouses"))
{
foreach (AvailableProperty prop in properties)
{
if (prop.PropertyType == "Townhouse")
{

lbxPropertyNumbers.Items.Add(prop.PropertyNumber.ToString());
lbxAddresses.Items.Add(prop.Address);
lbxCities.Items.Add(prop.City);
lbxStates.Items.Add(prop.State);
lbxZIPCodes.Items.Add(prop.ZIPCode);
lbxBedrooms.Items.Add(prop.Bedrooms);
lbxBathrooms.Items.Add(prop.Bathrooms);
lbxMarketValues.Items.Add(prop.MarketValue);
}
}
}

if
(lbxPropertiesTypes.CheckedItems.Contains("Condominiums"))
{
foreach (AvailableProperty prop in properties)
{
if (prop.PropertyType == "Condominium")
{

lbxPropertyNumbers.Items.Add(prop.PropertyNumber.ToString());
lbxAddresses.Items.Add(prop.Address);
lbxCities.Items.Add(prop.City);
lbxStates.Items.Add(prop.State);
lbxZIPCodes.Items.Add(prop.ZIPCode);
lbxBedrooms.Items.Add(prop.Bedrooms);
lbxBathrooms.Items.Add(prop.Bathrooms);
lbxMarketValues.Items.Add(prop.MarketValue);

C# 3.0 Practical Learning II 745


}
}
}
}

5. Return to the form and double-click the Close button

6. Implement its event as follows:


 
private void btnClose_Click(object sender, EventArgs e)
{
Close();
}

7. Execute the application and test the checked list box


 

C# 3.0 Practical Learning II 746


8. Close the form and return to your programming environment

9. To make sure that when a user clicks an item in one list box, the
corresponding item gets selected in the other list boxes, on the form,
click the Prop # list box

10. Press and hold Shift

11. Click each of the other list boxes

12. Release Shift

13. In the Properties window, click the Events button and double-click
SelectedIndexChanged

14. Implement the event as follows:


 
private void lbxPropertyNumbers_SelectedIndexChanged(object
sender, EventArgs e)
{
lbxMarketValues.SelectedIndex =
lbxBathrooms.SelectedIndex =
lbxBedrooms.SelectedIndex =
lbxZIPCodes.SelectedIndex =
lbxStates.SelectedIndex =

C# 3.0 Practical Learning II 747


lbxCities.SelectedIndex =
lbxAddresses.SelectedIndex =
lbxPropertyNumbers.SelectedIndex;
}

15. Return to the form

Automatically Checking an Item When Clicked


From its default implementation, when a checked list box is presented to the
user, when an item is clicked, its string gets highlighted but no check mark is
put in the box. To put a check mark on the item, the user must click it again.
This is not an anomaly. It is purposely so the user would know the difference
between an item that is selected and one that is checked.

To support the ability to automatically put a check mark on an item when the
user clicks it, the CheckedListBox provides the CheckOnClick Boolean
property. Its default value is False. If you want the items to be automatically
checked, set this property to true.

On an existing checked list box, to find out if the its items are automatically
checked, get the value of the CheckOnClick property.

Practical Learning: Automatically Checking an Item

1. On the form, click the checked list box

2. In the Properties window, double-click CheckOnClick to set its value to


True

3. Save the form

3-D Checked Items


After creating the list, each item appears with a flat check box to its left. If
you want a 3-D check box, you can change the Boolean ThreeDCheckBoxes
property from its False default to a True value:

ThreeDCheckBoxes 

False True 

C# 3.0 Practical Learning II 748


 

Windows Control: The Date Picker


Control
 

Introduction to the Date Picker Control


The Date and Time Picker is a control that allows the user to select either a
date or a time value. This control provides two objects in one:

C# 3.0 Practical Learning II 749


One of the advantages of the Date and Time Picker control is that it allows
the user to select a time or a date value instead of typing it. This
tremendously reduces the likelihood of mistakes.

Creating a Date/Time Picker

To create a Date or Time Picker control, add a DateTimePicker control to


a form or other container. The DateTimePicker control is based on the
DateTimePicker class. In reality, the DateTimePicker control can be
considered as two controls in one: you just have to choose which one of both
controls you want to use.

Introduction to the Date Picker


After adding the DateTimePicker control to the form, to allow the user to set
the dates and not the times on the control, set its Format property either to
Long or to Short.

Characteristics of the Date Picker


 

The Spin Button


After adding a date time picker control and setting its Format to either Long
(the default) or Short, the control becomes a combo box (the default). If you
do not like the combo box, you can display a spin button instead. This
characteristic is controlled by the ShowUpDown Boolean property. When its
value is set to False (the default), the control appears as a combo box. It you
set it to True, it appears as a spin button:

If the control displays a combo box and if the user clicks the arrow on the

C# 3.0 Practical Learning II 750


Date control, a calendar object similar to the month calendar control
displays:

The Check Box


In some cases, you may want to decide when to allow the user to select a
date or when to disable it. There are two ways you can do. You can use the
Control's Enabled property that all other controls inherit. Another technique
you can use is to display a check box on the left side of the text box section
of the control. The presence or absence of the check box is controlled by the
ShowCheckBox Boolean property whose default value is False. If you set it to
True, a check box appears:

When the check box is checked, the user can change the displayed date.
When the check box is unchecked, the control is displayed and the user
cannot change the date. The user must first put a check mark in the check
box in order to be able to change the date.

The state of the check box is controlled by the Boolean Checked property. If
the user clicks the check box to put a check mark in it, this property's value
becomes true. 

Using the Date Picker


As its name indicates, the date picker either displays a date or it allows the
user to specify a date. The control follows the format of the date values
specified in the regional settings of Control Panel. Consequently, the date is

C# 3.0 Practical Learning II 751


made of various sections including the name of the day, the name of the
month, the numeric day in the month, and the year.

If the control is equipped with a spin button, to change the month, the user
can click the month and then click one of the arrow buttons of the spin
control. The user can also use the arrow keys to get the same effect. In the
same way, the user can change the values of the day or the year.

If the control appears as a combo box, the user can click the arrow button.
This would display a calendar:

When the calendar displays, the control throws a DropDown event. The
DropDown event is of type EventArgs. This means that this event does not
carry any significant information, other than to let you know that the calendar
of the control has been dropped to display.

While the calendar is displaying, the user can change the month, change the
year, or click a date to select one. T user can still change the date in the text
box side of the control. However it is done, on the text box or on the
calendar, when the date of the control has been changed, the control fires a
ValueChanged event. The ValueChanged event, which is the default event of
the control, is of type EventArgs, meaning it does not give you any detail
about the date that was selected or about anything the user did. You would
use your own means of finding out what date the user had selected or
specified. This can easily be done by getting the Value property of the
control.

If the control is displaying a calendar, once the user clicks a date, the
calendar disappears and the control becomes a combo box again. When the
calendar retracts, the control fires a CloseUp event. The CloseUp event is of
type EventArgs, which means it does not carry any particular information
other than letting you know that the calendar has been closed.

The Calendar Visual Characteristics

C# 3.0 Practical Learning II 752


If the date picker control displays like a combo box, as mentioned already, if
the user clicks the arrow button, a calendar appears. The calendar shares the
same functionality and characteristics like the month calendar control:

 The background color of the title bar is represented by the


CalendarTitleBackColor property

 The color of the text on the calendar is handled by the


CalendarForeColor property

 The font used on the text throughout the calendar is set by the
CalendarFont property

 The background color of the calendar is set by the BackColor property

 The background color of the current month of the calendar is set by the
CalendarMonthBackground property

 The font color of the title bar is controlled by the


CalendarTitleForeColor property

 The minimum and the maximum dates are specified using the MinDate
and the MaxDate properties

 The color of the days of the trailing months is held by the


CalendarTrailingForeColor property

The Alignment of the Calendar


This calendar displays to the bottom-left or the bottom-right side of the
combo box. To control this alignment, change the value of the
DropDownAlign property whose default value is Left. The other value is
Right.

The displayed calendar object allows the user to select a date using the same
techniques we described for the alendar control. The calendar part of the
date time picker control displays using the same colors and other properties
as we saw with the calendar control. After the user has selected a date, the
date value displays in the text box section of the combo box and the calendar
disappears.

The Minimum and the Maximum Dates


If you want to control the range of dates the user can select, use the
MinDate and the MaxDate properties as we mentioned them from the
MonthCalendar control.

The Value of the Calendar

C# 3.0 Practical Learning II 753


When you add the date time picker control to your form or container, it
displays the date of the computer at the time the control was added. If you
want the control to display a different date, set the desired value in the Value
field of the Properties window. At any time, you can find out what value the
Date Picker has by retrieving the value of the Value property.

The Custom Format of the Calendar


If you set the Format property to Long, the date displays using the Long Date
formats of Control Panel. If you set the Format to Short, the control uses the
Short Date value of Control Panel. If you want to customize the way the date
is displayed, set the Format property to Custom. After setting the Format to
Custom, use the CustomFormat property to create the desired format. The
format is created by combining the following characters:

Format Used For Description

Displays the day as a number from 1 to


d Days
31

Displays the day as a number with a


dd Days
leading 0 if the number is less than 10

Displays a weekday name with 3 letters


ddd Weekdays
as Mon, Tue, etc

Displays the complete name of a week


dddd Weekdays
day as Monday, etc

M Months Displays the numeric month from 1 to 12

Displays the numeric month with a


MM Months
leading 0 if the number is less than 10

Displays the short name of the month as


MMM Months
Jan, Feb, Mar, etc

Displays the complete name of the


MMMM Months
month as January, etc

yy Years Displays two digits for the year as 00 for

C# 3.0 Practical Learning II 754


2000 or 03 for 2003

yyyy Years Displays the numeric year with 4 digits

This means that you should be reluctant to let the users type whatever they
want. The less they type, the less checking you need to do.

The Date Time Picker control uses some events that the month calendar
control does not have. Whenever the user changes the date or time value of
the control, a ValueChanged event fires. You can use this event to take some
action such as indicating to the user that the new date is invalid.

If the Format property of the control is set to Date and if the ShowUpDown
property is set to False, when the user clicks the arrow of the combo box to
display the calendar part of the date time picker control, the DropDown event
fires. On the other hand, if the user clicks the arrow to retract the calendar,
the CloseUp event fires. Both events are of EventArgs type.

Windows Controls: An Image List


 

Introduction
In some application that deals with graphic, you may use only one picture
but in various, if not most other applications, such as those used to display,
exchange, or switch pictures, you may deal with different pictures. In such a
type of application, sometimes the pictures are of different sizes, even
including unpredictable sizes. In another type of application, some of the
pictures you use may have the (exact) same size. For this type, instead of
using each picture individually, you can store them in a collection, then access
each picture when needed.

An image list is a collection of icons or pictures that are stored so that each
icon or picture can be located by an index. The icons or pictures must be of
the same size and they should be the same type. This means that the

C# 3.0 Practical Learning II 755


collection can be made of only icons of 16x16 sizes, only icons of 32x32 sizes,
only icons of 48x48 sizes, or only bitmaps (but of the same size each).

When it comes to design, there are two types of image lists. Each picture can
be added individually to the collection, or all of the pictures can be designed
in a longer picture and, inside of that long picture, you would use a technique
to locate each picture.

Once you get an image list, there is no pre-defined way you must use it.
Some Windows controls use an image list to use the pictures they need but
there are various other unpredictable ways you can use an image list.

Practical Learning: Introducing Image Lists

1. To create a new application, on the main menu, click File -> New ->
Project...

2. In the Templates list, click Windows Application

3. Set the name to ImageViewer1 and click OK

Creating an Image List


To support image lists, the .NET Framework provides a class called
ImageList that is defined in the System.Windows.Forms namespace of the
System.Windows.Forms.dll library. At design time, to create an image list,
from the Components section of the Toolbox, you can click the ImageList
button  and click the form.

To programmatically create an image list, declare a variable of type


ImageList and initialize it using one of its two constructors. The default
constructor is used to simply signal that you are going to use an image list.
Here is an example:
using System;
using System.Windows.Forms;

public class Exercise : Form


{
private ImageList lstImages;

public Exercise()
{
InitializeComponent();
}

void InitializeComponent()
{
lstImages = new ImageList();
}
}

C# 3.0 Practical Learning II 756


public class Program
{
public static int Main()
{
Application.Run(new Exercise());

return 0;
}
}

The ImageList class is equipped with another constructor whose syntax is:
public ImageList(IContainer container);

This constructor expects as argument the control container that will be


responsible for getting rid of the image list when the application exits.

Practical Learning: Creating an Image List

1. From the Components section of the Toolbox, click ImageList and click
the form

2. In the Properties window, change its Name to lstPictures

3. From the Components section of the Toolbox, click Timer and click the
form

4. In the Properties window, change its characteristics as follows:


Enabled: True
Interval: 2000

5. From the Common Controls section of the Toolbox, click PictureBox and
click the form

6. In the Properties window, change its characteristics as follows:


(Name): pbxViewer
Dock: Fill

7. Save all

Characteristics of an Image List

The Size of the Images


Before creating an image list, you must prepare the image(s). As mentioned
previously, you can use individual images that would be made into a set.
When creating the images, your primary concern is the size you give them.
The default size of a picture is 16x16.

C# 3.0 Practical Learning II 757


If you are creating a list of icons, you can create each with the default size of
16x16. In some cases (for example if you intend to use the images for a list
view), you can create or design a second set of icons whose size are 32x32
(and/or 48x48) each.

You can use a larger size:

 The maximum length a picture can have is 256 pixels

 The maximum height the picture can have is 256 pixels

To create or design your bitmaps, you can use either the bitmap designer of
Microsoft Visual Studio or you can use a more advanced external application
to prepare the pictures. Although the pictures used in an image list are
usually square (16x16, 32x32, 48x48, 96x96, etc), you can use a different
length and a different height but, if you are creating individual pictures, they
should each have the same size (same length and same height).

Instead of using different pictures, you can create one long picture whose
sections would be used to identify each picture. There is no particular way
you must design the long picture and there is no real rule about its
dimensions: the size would become an issue when it is time to use the
picture(s). Alternatively, when creating the picture, if it will include the
different pictures that would be considered in the list, make sure you know
where each sectional picture starts and where it ends. Here is an example:

C# 3.0 Practical Learning II 758


In this cases, there is one long picture made of different sections and each
section holds a particular picture. When creating this type, you must know the
size that holds each particular picture.

After preparing the pictures, you can get ready to create the image list. If you
want, you can specify the size of each picture before actually creating the list.
To support this, the ImageList class is equipped with a property named
ImageSize. The ImageSize property is of type Size. You can use it to
specify the size of each picture. Here is an example:
using System;
using System.Drawing;
using System.Windows.Forms;

public class Exercise : Form


{
private ImageList lstImages;

public Exercise()
{
InitializeComponent();
}

void InitializeComponent()
{
lstImages = new ImageList();
lstImages.ImageSize = new Size(256, 256);
}
}

If the image list has been created already, to find out the size of the picture,
you can get the value of the ImageSize property.

Practical Learning: Preparing the Pictures

1. Copy each of the following pictures and paste them in a directory or


folder of your computer
 

C# 3.0 Practical Learning II 759


2. Under the form, click lstPictures and, in the Properties window, set the
ImageSize to 250, 165

The Color Depth


Before creating the list of images, you must specify the number of bits that
will be used to specify the color of each pixel. This information is referred to
as the color depth. To support it, the ImageList class is equipped with a
property named ColorDepth. The possible values are Depth4Bit,
Depth8Bit, Depth16Bit, Depth24Bit, and Depth32Bit. The default value is
Depth8Bit.

Practical Learning: Specifying the Color Depht

 Under the form, click lstPictures and, in the Properties window, set the
ColorDeph to Depth32Bit

Creating the Collection of Images


After preparing the pictures, to visually create the list of images, under the
form, click the image list control to select it. Then:

 Click the arrow button on the control . Then click Choose


Images

C# 3.0 Practical Learning II 760


 

 In the Properties window, click the ellipsis button of the Images field

This would open the Images Collection Editor. To add a picture, you can click
the Add button, locate a picture and select it. You can continue doing this
until you have selected all necessary pictures. Here is an example:

After selecting the pictures, you can click OK.

To assist you with creating the list of images, the ImageList class is
equipped with a property named Images, which is a collection. The
ImageList.Images property is of type ImageCollection. The
ImageCollection class implements the IList, the ICollection, and the
IEnumerable interfaces.

Using the ImageCollection class through the Images property, you can add
the necessary icons or pictures one at a time. To help you with this, the
ImageCollection class implements the Add() method. If you are creating a
list of icons, you can call the following version of the Add() method:
public void Add(Icon value);

If you are creating a list of pictures, you can call the following version of the
Add() method:

C# 3.0 Practical Learning II 761


public void Add(Image value);

Here is an example:
public class Exercise : Form
{
private ImageList lstImages;

public Exercise()
{
InitializeComponent();
}

void InitializeComponent()
{
lstImages = new ImageList();
lstImages.ImageSize = new Size(256, 256);

Image img1 = Image.FromFile("E:\\Programs\\image1.jpg");


lstImages.Images.Add(img1);
Image img2 = Image.FromFile("E:\\Programs\\Image2.jpg");
lstImages.Images.Add(img2);
}
}

Instead of adding one picture at a time, you can first store them in an array.
To add an array of pictures, the ImageCollection class provides a method
named AddRange and whose syntax is:
public void AddRange(Image[] images);

Here is an example:
void InitializeComponent()
{
lstImages = new ImageList();
lstImages.ImageSize = new Size(256, 256);

Image img1 = Image.FromFile(@"E:\Programs\image1.jpg");


lstImages.Images.Add(img1);
Image img2 = Image.FromFile(@"E:\Programs\Image2.jpg");
lstImages.Images.Add(img2);

Image[] images =
{
Image.FromFile(@"E:\Programs\image3.jpg"),
Image.FromFile(@"E:\Programs\Image4.jpg"),
Image.FromFile(@"E:\Programs\Image5.jpg")
};

lstImages.Images.AddRange(images);
}

Practical Learning: Creating a List of Images

C# 3.0 Practical Learning II 762


1. Under the form, click lstPictures

2. In the Properties window, click Images and click the ellipsis button

3. In the Images Collection Editor, click Add, locate one of the pictures you
had saved, select it, and click Open

4. Do the same to select the other pictures


 

5. Click OK

Using an Image List


After creating an image list, you can use it in your application. As it name
implies, an image list is just a collection of images. The control that holds this
collection does not define why or when the images would be used. Some
Windows controls, such as the list view, the tab control or the toolbar, use
them. Most of the time, you will know when a certain control needs an image
list and how to use it. Otherwise, you can use the pictures in an image list in
various ways. For example, you can use those pictures like any others, such
as to display one on a form.

To support the ability to display the pictures of an image list, the ImageList
class is equipped with a method named Draw. When calling this method,
because the image list doesn't know where it would be used, and because the
target control would not define where the picture is coming from, the primary
argument to this method is the platform on which to display the picture. This
platform is a Graphics object. Once you have decided on the receiving
graphics, you must specified the location where the picture would be

C# 3.0 Practical Learning II 763


positioned. You have two primary options. You can specify the location by the
left and top coordinates. In this case, you would use the following version of
the Draw() method:
public void Draw(Graphics g, int x, int y, int index);

Alternatively, you can specify the location by a Point value. In this case, you
would use the following version of the method:
public void Draw(Graphics g, Point pt, int index);

In both cases, the last argument is the index of the desired picture within the
collection.

Practical Learning: Drawing the of Images

1. Under the form, double-click timer1 and change the file as follows:
 
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace ImageViewer1
{
public partial class Form1 : Form
{
static int index = 0;

public Form1()
{
InitializeComponent();
}

private void timer1_Tick(object sender, EventArgs e)


{
if (index < 6)
{
lstPictures.Draw(pbxViewer.CreateGraphics(),
pbxViewer.Left,
pbxViewer.Top,
index);
index++;
}
else
index = 0;
}
}
}

C# 3.0 Practical Learning II 764


2. Execute the application to see the result
 

3. Close the form and return to your programming environment

The Transparent Color


When drawing the pictures of an image list, you can designate one color that
the compiler will ignore or "see through". This is referred to as the
transparent color. To support this, the ImageList class is equipped with a
property named TransparentColor, which is of type Color.

Windows Control: Masked Text Box


 

Introduction
Microsoft Visual Basic 6.0 provides a convenient text box that allows you
to assist the user with text entry in a text box. This control is called MaskEdit.
To use this control, you must explicitly add it as a COM Component of the
Microsoft Masked Edit Control.

MaskEdit Characteristics
The most important property of a MaskEdit control, which sets it apart from
the (traditional) text box control, is its ability to control what the user can and

C# 3.0 Practical Learning II 765


cannot enter in the text side. To configure this text, you have two
alternatives. The Format property in the Properties window provides a list of
available masks you can use:

If none of the masks in the list suits you, you still have two alternatives. You
can type your own desired mask in the Format field. The characters you can
use are:

Date
Format Used For Description

Displays the day as a number from


d Days
1 to 31

Displays the day as a number with a


dd Days leading 0 if the number is less than
10

Displays a weekday name with 3


ddd Weekdays
letters as Mon, Tue, etc

Displays the complete name of a


dddd Weekdays
week day as Monday, etc

Displays the numeric month from 1


M Months
to 12

C# 3.0 Practical Learning II 766


Displays the numeric month with a
MM Months leading 0 if the number is less than
10

Displays the short name of the


MMM Months
month as Jan, Feb, Mar, etc

Displays the complete name of the


MMMM Months
month as January, etc

Displays two digits for the year as


yy Years
00 for 2000 or 03 for 2003

Displays the numeric year with 4


yyyy Years
digits

Besides these letters, an empty space and/or a special character should be


used to separate the sections of the string. You should use an appropriate
character as defined in the Regional Settings or the Customize Regional
Options of the Control Panel:

C# 3.0 Practical Learning II 767


Based on this, in US English, the character used to separate the date sections is
the forward slash if you use a short date. In US English, the comma is used to
separate the sections of a long date.

Time
Format Used For Description

Used to display the hour with


Hour for 12-
h one digit if the value is less
hour basis
than 10

Used to display the hour with


Hour for 12-
hh a leading 0 if the value is less
hour basis
than 10

Used to display the hour with


Hour for 24-
H one digit if the value is less
hour basis
than 10

HH Hour for 24- Used to display the hour with

C# 3.0 Practical Learning II 768


a leading 0 if the value is less
hour basis
than 10

Used to display the minute


m Minute with one digit if the value is
less than 10

Used to display the minute


mm Minute with a leading 0 if the value is
less than 10

Displays the letter A or P for


t AM/PM
the AM or PM section

Displays the letters AM or PM


tt AM/PM
for the last section

 
Besides the Format property, you can create a mask using the Mask field of
the Properties window. Both allow you to use many other characters to create
custom masks.

The Page Setup Dialog Box


 

Introduction
As opposed to directly printing a file, a user may want to perform some
preliminary preparation on the document or the printer. Microsoft Windows
provides another dialog box used to control printing. It is called Page Setup:

C# 3.0 Practical Learning II 769


To provide a Page Setup to your application, you can use the
PageSetupDialog button from the Toolbox. The PageSetupDialog control
is based on the PageSetupDialog class which derives from the
CommonDialog class.

Characteristics of the Page Setup Dialog Box


When using the Page Setup dialog box, the user must first select a printer.
This is usually done already by the operating system that selects the default
printer of the computer that called this dialog box. Otherwise, to select a
printer or to change the printer, the user can click the Printer button and
select or change it using the Name combo box:

C# 3.0 Practical Learning II 770


Displaying the Page Setup Printer dialog box also allows you and/or the user
to customize the printing process if necessary. If you want to do this, you can
use the PageSetupDialog.PrinterSettings property which is a value of
the PrinterSettings class reviewed earlier.

After selecting the printer, the user can click OK. The options of the Page
Setup dialog box depend on the driver of the printer selected in the Name
combo box. The Page Setup dialog box allows the user to customize the
appearance of the paper on which the document would be printed.

On the Page Setup, the user can click the arrow of the Size combo box and
select one of the configured sizes of paper. The characteristics of the paper
are controlled by the PageSettings class that we mentioned earlier. For
example, if the printer has many trays, as indicated by the driver of the
selected printer, the user can select which tray would be used when printing.
As it happens, one printer can have only one tray while another printer can
have 3, 5, or more trays.

If the desired printer is on a network, the user can click the Network button
to locate it. To programmatically show or hide the Network button, specify a
false or true result to the PageSetupDialog.ShowNetwork Boolean property.

The user also has the option to print the document in Portrait (vertical) or in
Landscape (horizontal) position. The option to allow the user to select Portrait
or Landscape is controlled by the AllowOrientation Boolean property.

C# 3.0 Practical Learning II 771


Windows Control: The Progress Bar
 

Description
A progress bar is a control that displays (small) rectangles that are each filled
with a color. These (small) rectangles are separate but adjacent each other so
that, as they display, they produce a bar. To have the effect of a progress
bar, not all these rectangles display at the same time. Instead, a numeric
value specifies how many of these (small) rectangles can display at one time.

Creating a Progress Bar


To support progress bars, the .NET Framework provides the ProgressBar
class, which is derived from the Control class. In the Toolbox, the progress
bar is represented by the ProgressBar control. At design time, to get a
progress bar, from the Common Controls section of the Toolbox, you can click
the ProgressBar control and click the form (or another container).

To programmatically get a progress bar, declare a variable of type


ProgressBar, use the new operator to allocate memory for it, and add it to
the Controls property of its container. Here is an example:
using System;
using System.Drawing;
using System.Windows.Forms;

public class Exercise : System.Windows.Forms.Form


{
ProgressBar progress;

public Exercise()
{
InitializeComponent();
}

private void InitializeComponent()


{
Text = "Progressive Studies";
Size = new Size(242, 80);

progress = new ProgressBar ();

Controls.Add(progress);

C# 3.0 Practical Learning II 772


}
}

public class Program


{
static int Main()
{
System.Windows.Forms.Application.Run(new Exercise());
return 0;
}
}

This would produce:

Characteristics of a Progress Bar


 

Introduction
The progress bar shares the various characteristics of other graphical controls
(that is, the objects derived from the Control class). These include the
location, the size, the back color, the size, the cursor, the ability to be
anchored, the ability to the docked, the ability to be shown or hidden, and the
ability to be enabled or disabled, etc.

Here is an example:

private void InitializeComponent()


{
Text = "Progressive Studies";
Size = new Size(282, 80);

progress = new ProgressBar ();


progress.Location = new Point(12, 12);
progress.Width = 252;

Controls.Add(progress);

C# 3.0 Practical Learning II 773


}

This would produce:

After adding it to an application, a progress bar assumes a horizontal


position (the actual progress bar of Microsoft Windows, as implemented in
Win32, can also have a vertical orientation; the .NET Framework's version has
this and other limitations).

The Minimum and Maximum


To show its effect, the progress bar draws its small rectangles as a bar. These
small rectangles are from a starting position to an ending position. This
means that the progress bar uses a range of values. This range is controlled
by the Minimum and the Maximum properties whose default values are 0 and
100 respectively. At design time, you can set them using the limits of an
integer. To programmatically set these values, assign the desired numbers to
one or both. Here is an example:
private void InitializeComponent()
{
Text = "Progressive Studies";
Size = new Size(282, 80);

progress = new ProgressBar ();


progress.Location = new Point(12, 12);
progress.Width = 252;

progress.Minimum = 0;
progress.Maximum = 255;

Controls.Add(progress);
}

The small rectangles would be drawn from the left (the Minimum value) to the
right (the Maximum value) sides of the control.

The Value of a Progress Bar


At one particular time, the most right rectangle of a progress bar is referred
to as its position and it is represented by the Value property. At design time,
to set a specific position for the control, change the value of the Value
property whose default is 0. The position must always be between the
Minimum and Maximum values. At design time, if you change the Minimum to a
value higher than the Value property, the value of Value would be increased

C# 3.0 Practical Learning II 774


to the new value of Minimum. If you set the value of Value to a value lower
than the Minimum, You would receive an error:

After clicking OK, the value of the Minimum would be reset to that of the
Value property. In the same way, if you set the value of Value to a value
higher than Maximum, you would receive an error.

At run time, you can assign the desired value to the Value property. Once
again, avoid specifying a value that is out of range. Here is an example:
private void InitializeComponent()
{
Text = "Progressive Studies";
Size = new Size(282, 80);

progress = new ProgressBar ();


progress.Location = new Point(12, 12);
progress.Width = 252;

progress.Minimum = 0;
progress.Maximum = 255;

progress.Value = 88;

Controls.Add(progress);
}

This would produce:

C# 3.0 Practical Learning II 775


The Step Value of a Progress Bar
Because a progress bar is usually meant to indicate the progress of an
activity, when drawing its small rectangles, it increases its current position in
order to draw the next rectangle, except if the control is reset. The number of
units that the object must increase its value to is controlled by the Step
property. By default, it is set to 10. Otherwise, you can set it to a different
value of your choice. Here is an example:
private void InitializeComponent()
{
Text = "Progressive Studies";
Size = new Size(282, 80);

progress = new ProgressBar ();


progress.Location = new Point(12, 12);
progress.Width = 252;

progress.Minimum = 0;
progress.Maximum = 255;
progress.Value = 88;

progress.Step = 12;

Controls.Add(progress);
}

When the control draws one of its rectangles based on the Step value, it calls
the PerformStep(). Its syntax is:
public void PerformStep();

After a small rectangle has been drawn, the current value is incremented by
the value of the Step property. If you want to increase the value of the
control to a value other than that of the Step property, you can call the
Increment() method. Its syntax is:

public void Increment(int value);

The amount by which to increment is passed to the method. Here is an


example:
using System;
using System.Drawing;
using System.Windows.Forms;

public class Exercise : System.Windows.Forms.Form


{
ProgressBar progress;
Button btnIncrement;

public Exercise()
{
InitializeComponent();

C# 3.0 Practical Learning II 776


}

void InitializeComponent()
{
Text = "Progressive Studies";
Size = new Size(284, 115);

progress = new ProgressBar ();


progress.Location = new Point(12, 12);
progress.Width = 252;

progress.Minimum = 0;
progress.Maximum = 255;
progress.Value = 88;
progress.Step = 12;

btnIncrement = new Button();


btnIncrement.Text = "Increment";
btnIncrement.Location = new Point(12, 52);
btnIncrement.Click += new
EventHandler(btnIncrementClick);

Controls.Add(progress);
Controls.Add(btnIncrement);
}

void btnIncrementClick(object sender, EventArgs e)


{
progress.Increment(8);
}
}

public class Program


{
static int Main()
{
System.Windows.Forms.Application.Run(new Exercise());
return 0;
}
}

The Style of a Progress Bar


So far, we have described a progress bar as drawing small rectangles to
represent the control. These rectangles are visually distinct (don't touch each
other) and adjacent. As an alternative, if you want the progress control to
appear smooth, you can make the control draw each next rectangle exactly
where the previous one stops. To support this characteristic, the
ProgressBar class is equipped with the Style property.

The ProgressBar.Style property is based on the ProgressBarStyle


enumeration that has three members:

C# 3.0 Practical Learning II 777


 Blocks: With this value, the progress bar draws small distinct and
adjacent rectangles:
 

 Continuous: The progress bar appears smooth as the same rectangles


are not separated:
 

 Marquee: The progress bar shows an animation that consists of drawing


a group of small rectangles that keep moving from left to right and
restart

If you decide to use the Marquee style, the progress bar will continually show
its animation of small rectangles moving at a speed set from the
MarqueeAnimationSpeed integral property and you cannot get the value of
the progress bar.

Windows Control: The Split


Container
 

Introduction
A splitter is an object that divides a container in two vertical or two
horizontal sections. It makes it possible for one section to be enlarged,
narrowed, heightened, or shrunk while the other section is narrowed,
enlarged, shrunk, or heightened. Based on this behavior, one section gets
more room while the other gets smaller. You are probably familiar with this
description if you have used Windows Explorer. In most cases, a splitter is
made obvious by displaying a bar that divides the sections.

C# 3.0 Practical Learning II 778


Before using a splitter, the user can position the mouse of its bar. The cursor
would change into a horizontal or a vertical double-arrow, depending on the
orientation of the splitter. Here is an example:

To use the splitter, the user can click its bar and drag it left, right, up, or
down, depending on the orientation of the splitter and what the user is trying
to accomplish. After getting the desired position, the user can release the
mouse.

Creating a Splitter
To support splitters, the .NET Framework provides the split container. It is
represented in the library by the SplitContainer class and in the Toolbox
by the SplitContainer object. To add a split container to your application,
from the Containers section of the Toolbox, click the SplitContainer object
and click a form of your application. Once you do this, an object called a
split container fills the form, divides itself in two, and gets equipped with two
objects named Panel1 and Panel2. In reality, a split container is an object
made of two panels separated by a bar. In each panel, you can then add the
controls as you see fit. A control added to one of the panels would become a
child of that panel.

A split container itself resembles a panel control. As described above, after


you have added it, it automatically set its Dock property to Fill. This means
that, after adding a split container, you would have difficulties adding an
object to the form but outside the split container. Therefore, if you intend to

C# 3.0 Practical Learning II 779


have objects that do not belong to the split container, you must perform
some prerequisite actions. Typically, you would first add a panel (or another
container) to a form. For example, to have a group of control in the top
section of the form, you can first add a panel to it and set its Dock property
to Top:

Then, when you add a split container, it can use only the remaining area of
the form:

In the same way, before adding a split container, you should prepare the
form for objects you want to place on the form but that would not belong to
the split container.

Just you can have a split container made of two parts, you can have more
than two resizable sections. To do this, after adding a split container, add
another split container to one of the panels of an existing split container.

Characteristics of a Split Container

C# 3.0 Practical Learning II 780


 

Introduction
After adding a split container to a form, it may become difficult to select it
from the form. To select, use the combo box above the Properties window. If
you click an area of the split container, the corresponding panel becomes
selected and you can change its characteristics using the Properties window
but you can neither move nor delete a panel from the split container.

As mentioned already, a split container is made of two panels separated by a


bar. Each panel is equipped with the necessary characteristics that facilitate
its role as its own container, including the background color, the background
image, the ability to show the scroll bars, etc.

As mentioned already, after adding a split container to a form, it sets its Dock
property to Fill. This is the default behavior. If you do not want the
container to fill the available area of the form, you can change the value of its
Dock property.

The Background of a Split Container


Like a visual control, you can make a split container more appealing by
painting its background with a picture. To support this, the SplitContainer
class is equipped with a a property named BackgroundImage. This property
expects a picture file or its location. The background image would appear on
the splitter. When you set or change the background picture of the split
container, it fires an BackgroundImageChanged event. This event is of type
EventArgs.

Because each panel has the ability to show a picture and to hold their
controls, their backgrounds take priority over the background of the split
container.

The Size of the Splitter


In our description, we saw that a split container was made of a dividing bar.
This bar appears with a 4 pixel width. If you want, you can make it larger
than. This characteristic is controlled by the SplitterWidth property. Its
default value is 4 pixel. To change the with, assign the desired integer value
to the SplitContainer.SplitterWidth property.

The Orientation of the Splitter


By default, when you add a new split container to a form, it divides itself with
vertical bar. This makes it possible to change the width of panels.
Alternatively, if you want the control to be divided horitally, you must change
the orientation of the bar. To support this, the SplitContainer class is

C# 3.0 Practical Learning II 781


equipped with a property named Orientation. Default value of the
SplitContainer.Orientation property is Vertical. To divide the container
horizontally, set this property to Horizontal.

Moving the Splitter


As mentioned in our description, to use a splitter, the user can position the
mouse on the bar and drag in the desired direction. This is allowed by default
and is controlled by the IsSplitterFixed Boolean property whose default
value is False. While the user is moving the splitter, the split container fires a
SplitterMoving event. This is event is handled by the
SplitterCancelEventArgs class. This class holds the x and y coordinates of
the split container as well the x and y coordinates of the mouse. After the
user has moved the splitter, the split container fires a SplitterMoved event.
This is event is handled by the SplitterEventArgs class that gives the x
and y coordinates of the splitter.

To prevent the user fromdragging the bar, you can set the
SplitContainer.IsSplitterFixed property to True. If you do this, when
the user positions the mouse on the bar, the cursor would keep its pointing
arrow shape.

The Splitter Increment


If the IsSplitterFixed property is set to False, which is the default, the
user can drag the bar to resize the panels. By default, when the user drags
the bar, it moves by one pixel. You can make it move faster than that. This
characteristic is controlled by the SplitterIncrement property whose
default value is 1 (pixel). To make the bar move by more than one pixel,
assign the desired value to the SplitterIncrement property.

Fixing a Panel
After adding a split container and if the Dock property of the control is to a
value other than None, when the user resizes the form, the border of the split
container follows the movement of the mouse and the bar also moves by a
certain rate to resize the opposite panel:

C# 3.0 Practical Learning II 782


If you want, you can fix one panel so that, when the form is resized, that
panel would keep its size by the bar not moving. To support this, the
SplitContainer class is equipped with a property named FixedPanel. You
can select one of the panels as the value of this property.

Windows Control: The Timer


 

Introduction
A timer is a non-spatial object that uses recurring lapses of time in a
computer or in your application. To work, every lapse of period, the
control sends a message to the operating system. The message is something
to the effect of "I have counted the number of lapses you asked me to
count".

As opposed to the time that controls your computer, a timer is partly but
greatly under your control. Users do not see nor do they use a timer as a
control. As a programmer, you decide if, why, when, and how to use this
control.

To support timers, the .NET Framework provides the Timer control from the
Toolbox and it is implemented through the Timer class. To add it to your
application at design time, on the Toolbox, click Timer and click the form.

Practical Learning: Introducing the Timer Control

1. Start a new Windows Application named ScreenSaver1

C# 3.0 Practical Learning II 783


2. Change the following properties of the form:
BackColor: Black
FormBorderStyle: None
WindowState: Maximized

3. In the Properties window, click the Events button and double-click


MouseMove

4. Implement the event as follows:


 
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace ScreenSaver1
{
public partial class Form1 : Form
{
static int MoveCounter = 0;

public Form1()
{
InitializeComponent();
}

private void Form1_MouseMove(object sender,


MouseEventArgs e)
{
Cursor.Hide();

if (MoveCounter == 20)
Close();
MoveCounter++;
}
}
}

5. Display the form again and, in the Events section of the Properties
window, double-click KeyDown

6. Implement its event as follows:


 
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
// If the user presses Esc, stop the screen saver
if (e.KeyCode == Keys.Escape)
Close();
}

C# 3.0 Practical Learning II 784


7. Execute the application to test it (to close the form, you will just move
the mouse or press Esc)

8. Display the form

Characteristics of a Timer
A timer is an object used to count lapses of time and send a message when it
has finished counting. Each count is called a tick. When a tick occurs, the
control fires a Tick event. This Tick event is of type EventArgs, meaning
that it doesn't provide more information than to let you know that a lapse has
occurred.

The amount of time allocated for counting is called an interval and it is


represented by the Interval property. The Interval is a very important
characteristic of the Timer control because it measures and controls the total
time needed to perform a complete count. The Interval is measured in
milliseconds. Like any counter, the lower the value, the faster the count will
finish, and the higher the value, the longer the count (if you ask one kid to
count from 1 to 10 and you ask another to count from 1 to 20 at the same
time, if you ask them to shout when they finish, the first kid would finish first
and would shout first). The amount of interval you specify will depend on
what you are trying to do.

In order for a timer to count, you must tell it when it should start counting. In
some applications, you may want the control to work full-time while in some
other applications, you may want the control to work only in response to an
intermediate event. The ability to stop and start a Timer control can be set
using the Enabled Boolean property. When, or as soon as, this property is set
to true, the control starts counting. You can also make it start by calling the
Timer.Start() method. Its syntax is:

public void Start();

If, when, or as soon as, the Enabled property is set to false, the control stops
and resets its counter to 0. You can also stop the timer by calling the
Timer.Stop() method. Its syntax is:

public void Stop();

Practical Learning: Using Timer Controls

1. From the Components section of the Toolbox, click the Timer control
and click the form

C# 3.0 Practical Learning II 785


2. In the Properties window, set the Enabled property to True and set the
Interval to 200

3. Under the form, double-click the timer

4. In the top section of the file, under the other using System lines, type
using System.Drawing.Drawing2D;

5. Scroll down and implement the Tick event as follows:


 
private void timer1_Tick(object sender, EventArgs e)
{
// Get the Graphics object of the form
Graphics graph = Graphics.FromHwnd(this.Handle);

// Generate a random number


Random rndNumber = new Random(DateTime.Now.Millisecond);

// Create a list of the colors of the .NET Framework


Color[] curColor =
{
Color.AliceBlue, Color.AntiqueWhite, Color.Aqua,
Color.Aquamarine,
Color.Azure, Color.Beige, Color.Bisque, Color.Black,
Color.BlanchedAlmond, Color.Blue,
Color.BlueViolet, Color.Brown,
Color.BurlyWood, Color.CadetBlue,
Color.Chartreuse, Color.Chocolate,
Color.Coral, Color.CornflowerBlue, Color.Cornsilk,
Color.Crimson,
Color.Cyan, Color.DarkBlue, Color.DarkCyan,
Color.DarkGoldenrod,
Color.DarkGray, Color.DarkGreen,
Color.DarkKhaki, Color.DarkMagenta,
Color.DarkOliveGreen, Color.DarkOrange, Color.DarkOrchid,
Color.DarkRed, Color.DarkSalmon, Color.DarkSeaGreen,
Color.DarkSlateBlue, Color.DarkSlateGray,
Color.DarkTurquoise,
Color.DarkViolet, Color.DeepPink, Color.DeepSkyBlue,
Color.DimGray,
Color.DodgerBlue, Color.Firebrick, Color.FloralWhite,
Color.ForestGreen,
Color.Fuchsia, Color.Gainsboro, Color.GhostWhite,
Color.Gold,
Color.Goldenrod, Color.Gray, Color.Green,
Color.GreenYellow,
Color.Honeydew, Color.HotPink, Color.IndianRed,
Color.Indigo,
Color.Ivory, Color.Khaki, Color.Lavender,
Color.LavenderBlush,
Color.LawnGreen, Color.LemonChiffon, Color.LightBlue,
Color.LightCoral, Color.LightCyan,
Color.LightGoldenrodYellow,

C# 3.0 Practical Learning II 786


Color.LightGray, Color.LightGreen, Color.LightPink,
Color.LightSalmon,
Color.LightSeaGreen, Color.LightSkyBlue,
Color.LightSlateGray,
Color.LightSteelBlue, Color.LightYellow, Color.Lime,
Color.LimeGreen,
Color.Linen, Color.Magenta, Color.Maroon,
Color.MediumAquamarine,
Color.MediumBlue, Color.MediumOrchid, Color.MediumPurple,
Color.MediumSeaGreen, Color.MediumSlateBlue,
Color.MediumSpringGreen,
Color.MediumTurquoise, Color.MediumVioletRed,
Color.MidnightBlue,
Color.MintCream, Color.MistyRose, Color.Moccasin,
Color.NavajoWhite,
Color.Navy, Color.OldLace, Color.Olive, Color.OliveDrab,
Color.Orange,
Color.OrangeRed, Color.Orchid, Color.PaleGoldenrod,
Color.PaleGreen,
Color.PaleTurquoise, Color.PaleVioletRed,
Color.PapayaWhip,
Color.PeachPuff, Color.Peru, Color.Pink, Color.Plum,
Color.PowderBlue,
Color.Purple, Color.Red, Color.RosyBrown,
Color.RoyalBlue,
Color.SaddleBrown, Color.Salmon, Color.SandyBrown,
Color.SeaGreen,
Color.SeaShell, Color.Sienna, Color.Silver,
Color.SkyBlue,
Color.SlateBlue, Color.SlateGray, Color.Snow,
Color.SpringGreen,
Color.SteelBlue, Color.Tan, Color.Teal, Color.Thistle,
Color.Tomato,
Color.Transparent, Color.Turquoise, Color.Violet,
Color.Wheat,
Color.White, Color.WhiteSmoke, Color.Yellow,
Color.YellowGreen
};

// Create a list of 10 rectangles for each row


Rectangle[] row1 = new Rectangle[10];
Rectangle[] row2 = new Rectangle[10];
Rectangle[] row3 = new Rectangle[10];
Rectangle[] row4 = new Rectangle[10];
Rectangle[] row5 = new Rectangle[10];
Rectangle[] row6 = new Rectangle[10];
Rectangle[] row7 = new Rectangle[10];
Rectangle[] row8 = new Rectangle[10];

// Create the rectangles that will be drawn on the


screen
for (int i = 0; i < 9; i++)
{
row1[i] = new Rectangle(i + (i * (Width / 10)),
0,
(Width - 36) / 10, Height / 8);

C# 3.0 Practical Learning II 787


row2[i] = new Rectangle(i + (i * (Width / 10)),
4 + (Height / 8),
(Width - 36) / 10, Height / 8);

row3[i] = new Rectangle(i + (i * (Width / 10)),


8 + (2 * (Height / 8)),
(Width - 36) / 10, Height / 8);

row4[i] = new Rectangle(i + (i * (Width / 10)),


12 + (3 * (Height / 8)),
(Width - 36) / 10, Height / 8);

row5[i] = new Rectangle(i + (i * (Width / 10)),


16 + (4 * (Height / 8)),
(Width - 36) / 10, Height / 8);

row6[i] = new Rectangle(i + (i * (Width / 10)),


20 + (5 * (Height / 8)),
(Width - 36) / 10, Height / 8);

row7[i] = new Rectangle(i + (i * (Width / 10)),


24 + (6 * (Height / 8)),
(Width - 36) / 10, Height / 8);

row8[i] = new Rectangle(i + (i * (Width / 10)),


28 + (7 * (Height / 8)),
(Width - 36) / 10, Height / 8);
}

// Create the last rectangle of each row


Rectangle row1a = new Rectangle(9 + (9 * (Width / 10)),
0, ((Width - 36) / 10) - 2,
Height / 8);
Rectangle row2a = new Rectangle(9 + (9 * (Width / 10)),
4 + (Height / 8), ((Width - 36) / 10) -
2, Height / 8);
Rectangle row3a = new Rectangle(9 + (9 * (Width / 10)),
8 + (2 * (Height / 8)), ((Width -
36) / 10) - 2, Height / 8);
Rectangle row4a = new Rectangle(9 + (9 * (Width / 10)),
12 + (3 * (Height / 8)), ((Width -
36) / 10) - 2, Height / 8);
Rectangle row5a = new Rectangle(9 + (9 * (Width / 10)),
16 + (4 * (Height / 8)), ((Width
- 36) / 10) - 2, Height / 8);
Rectangle row6a = new Rectangle(9 + (9 * (Width / 10)),
20 + (5 * (Height / 8)), ((Width
- 36) / 10) - 2, Height / 8);
Rectangle row7a = new Rectangle(9 + (9 * (Width / 10)),
24 + (6 * (Height / 8)), ((Width
- 36) / 10) - 2, Height / 8);
Rectangle row8a = new Rectangle(9 + (9 * (Width / 10)),
28 + (7 * (Height / 8)), ((Width
- 36) / 10) - 2, Height / 8);

C# 3.0 Practical Learning II 788


// Create a list of the hatch brushes of the .NET
Framework using random colors
HatchBrush[] curBrush =
{
new HatchBrush(HatchStyle.BackwardDiagonal,

curColor[rndNumber.Next(curColor.Length)],

curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.Cross,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.DarkDownwardDiagonal,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.DarkHorizontal,
curColor[rndNumber.Next(curColor.Length)],

curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.DarkUpwardDiagonal,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.DarkVertical,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.DashedDownwardDiagonal,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.DashedHorizontal,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.DashedUpwardDiagonal,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.DashedVertical,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.DashedVertical,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.DiagonalBrick,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.DiagonalCross,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.Divot,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.DottedDiamond,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.DottedGrid,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.ForwardDiagonal,

C# 3.0 Practical Learning II 789


curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.Horizontal,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.HorizontalBrick,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.LargeCheckerBoard,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.LargeConfetti,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.LargeGrid,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.LightDownwardDiagonal,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.LightHorizontal,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.LightUpwardDiagonal,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.LightVertical,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.Max,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.Min,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.NarrowHorizontal,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.NarrowVertical,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.OutlinedDiamond,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.Percent05,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.Percent10,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.Percent20,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.Percent25,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),

C# 3.0 Practical Learning II 790


new HatchBrush(HatchStyle.Percent30,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.Percent40,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.Percent50,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.Percent60,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.Percent70,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.Percent75,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.Percent80,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.Percent90,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.Plaid,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.Percent05,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)])
};

// Draw the rectangles to cover the screen


for (int i = 0; i < 9; i++)
{

graph.FillRectangle(curBrush[rndNumber.Next(curBrush.Length)],
row1[i]);
graph.DrawRectangle(new
Pen(curBrush[rndNumber.Next(curBrush.Length)]), row1[i]);

graph.FillRectangle(curBrush[rndNumber.Next(curBrush.Length)],
row2[i]);
graph.DrawRectangle(new
Pen(curBrush[rndNumber.Next(curBrush.Length)]), row2[i]);

graph.FillRectangle(curBrush[rndNumber.Next(curBrush.Length)],
row3[i]);
graph.DrawRectangle(new
Pen(curBrush[rndNumber.Next(curBrush.Length)]), row3[i]);

graph.FillRectangle(curBrush[rndNumber.Next(curBrush.Length)],
row4[i]);

C# 3.0 Practical Learning II 791


graph.DrawRectangle(new
Pen(curBrush[rndNumber.Next(curBrush.Length)]), row4[i]);

graph.FillRectangle(curBrush[rndNumber.Next(curBrush.Length)],
row5[i]);
graph.DrawRectangle(new
Pen(curBrush[rndNumber.Next(curBrush.Length)]), row5[i]);

graph.FillRectangle(curBrush[rndNumber.Next(curBrush.Length)],
row6[i]);
graph.DrawRectangle(new
Pen(curBrush[rndNumber.Next(curBrush.Length)]), row6[i]);

graph.FillRectangle(curBrush[rndNumber.Next(curBrush.Length)],
row7[i]);
graph.DrawRectangle(new
Pen(curBrush[rndNumber.Next(curBrush.Length)]), row7[i]);

graph.FillRectangle(curBrush[rndNumber.Next(curBrush.Length)],
row8[i]);
graph.DrawRectangle(new
Pen(curBrush[rndNumber.Next(curBrush.Length)]), row8[i]);
}

graph.FillRectangle(curBrush[rndNumber.Next(curBrush.Length)],
row1a);
graph.DrawRectangle(new
Pen(curBrush[rndNumber.Next(curBrush.Length)]), row1a);

graph.FillRectangle(curBrush[rndNumber.Next(curBrush.Length)],
row2a);
graph.DrawRectangle(new
Pen(curBrush[rndNumber.Next(curBrush.Length)]), row2a);

graph.FillRectangle(curBrush[rndNumber.Next(curBrush.Length)],
row3a);
graph.DrawRectangle(new
Pen(curBrush[rndNumber.Next(curBrush.Length)]), row3a);

graph.FillRectangle(curBrush[rndNumber.Next(curBrush.Length)],
row4a);
graph.DrawRectangle(new
Pen(curBrush[rndNumber.Next(curBrush.Length)]), row4a);

graph.FillRectangle(curBrush[rndNumber.Next(curBrush.Length)],
row5a);
graph.DrawRectangle(new
Pen(curBrush[rndNumber.Next(curBrush.Length)]), row5a);

graph.FillRectangle(curBrush[rndNumber.Next(curBrush.Length)],
row6a);

C# 3.0 Practical Learning II 792


graph.DrawRectangle(new
Pen(curBrush[rndNumber.Next(curBrush.Length)]), row6a);

graph.FillRectangle(curBrush[rndNumber.Next(curBrush.Length)],
row7a);
graph.DrawRectangle(new
Pen(curBrush[rndNumber.Next(curBrush.Length)]), row7a);

graph.FillRectangle(curBrush[rndNumber.Next(curBrush.Length)],
row8a);
graph.DrawRectangle(new
Pen(curBrush[rndNumber.Next(curBrush.Length)]), row8a);
}

6. Execute the application

Windows Control: The Tree View


 

Introduction
A tree view is a control that resembles an upside
down tree and displays a hierarchical list of items.
Like a normal tree, a tree view starts in the top
section with an object referred to as the root. Under
the root, a real tree is made of branches and leaves.
In an application, a tree view is only made of
branches and each branch is called a node. In real
world, a leaf cannot have a branch as its child, only
a branch can have another branch as its child and a
branch can have a leaf as a child. In an application,
a node (any node) can have a node as a child.

Like a real world tree, the branches or nodes of a


tree view use a type of relationship so that they are
not completely independent. For example, a tree
view can be based on a list that has a parent item
and other child items that depend on that parent. In
real world, if you cut a branch, the branches and
leaves attached to it also disappear. This scenario is
also valid for a tree view.

Most of the time, a tree has only one root but a tree
in an application can have more than one root.

C# 3.0 Practical Learning II 793


Tree View Creation
In a Windows application a tree view is primarily a control like any other. To
use it in your application, you can click the TreeView button in the Toolbox
and click a form or other control in your application. This is equivalent to
programmatically declaring a variable of type TreeView, using the new
operator to instantiate it and adding it to its container's list of controls
through a call to the Controls.Add() method. Here is an example:

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

public class Exercise : System.Windows.Forms.Form


{
TreeView tvwCountries;

public Exercise()
{
InitializeComponent();
}

private void InitializeComponent()


{
Text = "Countries Statistics";
Size = new Size(242, 280);

tvwCountries = new TreeView();

tvwCountries.Location = new Point(12, 12);


tvwCountries.Width = 210;
tvwCountries.Height = 230;

Controls.Add(tvwCountries);
}
}

public class Program


{
static int Main()
{
System.Windows.Forms.Application.Run(new Exercise());
return 0;
}
}

This would produce:

C# 3.0 Practical Learning II 794


Using a TreeView variable only adds a rectangular empty control to your
application. The next action you probably take is to add one or more
branches to the tree.

Practical Learning: Introducing the Tree View Control

1. Start Microsoft Visual C#

2. Create a new Windows Application named CollegeParkAutoParts2

3. In the Solution Explorer, right-click Form1.cs and click Rename

4. Type Central.cs and press Enter

5. Design the form as follows:


 

C# 3.0 Practical Learning II 795


Control Text Name Other Properties

College Park Font: Times New Roman,


Label  
Auto-Parts 20.25pt, style=Bold

Panel     Height: 2

TreeView   tvwAutoParts  

GroupBox      

ListView   lvwAutoParts View: Details

C# 3.0 Practical Learning II 796


(Name) Text TextAlign Width

colPartNumber Part #    
Columns  
colPartName Part Name   300

colUnitPrice Unit Price Right 80

GroupBox Selected Parts    

Label Part #    

Label Part Name    

Label Unit Price    

Label Qty    

Label Sub Total    

TextBox   txtPartNumber1  

TextBox   txtPartName1  

TextBox 0.00 txtUnitPrice1 TextAlign: Right

TextBox 0 txtQuantity1 TextAlign: Right

TextBox 0.00 txtSubTotal1 TextAlign: Right

C# 3.0 Practical Learning II 797


Button Remove btnRemove1  

TextBox   txtPartNumber2  

TextBox   txtPartName2  

TextBox 0.00 txtUnitPrice2 TextAlign: Right

TextBox 0 txtQuantity2 TextAlign: Right

TextBox 0.00 txtSubTotal2 TextAlign: Right

Button Remove btnRemove2  

TextBox   txtPartNumber3  

TextBox   txtPartName3  

TextBox 0.00 txtUnitPrice3 TextAlign: Right

TextBox 0 txtQuantity3 TextAlign: Right

TextBox 0.00 txtSubTotal3 TextAlign: Right

Button Remove btnRemove3  

TextBox   txtPartNumber4  

TextBox   txtPartName4  

C# 3.0 Practical Learning II 798


TextBox 0.00 txtUnitPrice4 TextAlign: Right

TextBox 0 txtQuantity4 TextAlign: Right

TextBox 0.00 txtSubTotal4 TextAlign: Right

Button Remove btnRemove4  

TextBox   txtPartNumber5  

TextBox   txtPartName5  

TextBox 0.00 txtUnitPrice5 TextAlign: Right

TextBox 0 txtQuantity5 TextAlign: Right

TextBox 0.00 txtSubTotal5 TextAlign: Right

Button Remove btnRemove5  

TextBox   txtPartNumber6  

TextBox   txtPartName6  

TextBox 0.00 txtUnitPrice6 TextAlign: Right

TextBox 0 txtQuantity6 TextAlign: Right

TextBox 0.00 txtSubTotal6 TextAlign: Right

C# 3.0 Practical Learning II 799


Button Remove btnRemove6  

GroupBox Order Summary    

Button New Auto-Part... btnNewAutoPart  

Label Total Order:    

TextBox 0.00 txtTotalOrder  

Button Close btnClose  

6. Execute the application to test it

7. Close the form and return to your programming environment

Introduction to Creating Tree View


Nodes
 

Visually Creating Nodes


In a Windows application a tree view is primarily a control like any other. To
use it in your application, you can click the TreeView button in the Toolbox
and click a form or other control in your application. This is equivalent to
programmatically declaring a variable of type TreeView, using the new
operator to instantiate it and adding it to its container's list of controls
through a call to the Controls.Add() method. Here is an example:

To create the nodes of a tree view, Microsoft Visual Studio provides a


convenient dialog box you can use at design time. To display it, after adding
a tree view control to a form, you can click the ellipsis button of its Nodes
field in the Properties window. This would open the TreeNode Editor:

C# 3.0 Practical Learning II 800


The primary characteristic of a node is the text it displays. At design time and
in the TreeNode Editor, to create a node, you can click the Add Root button.
When you do this, a node with a default but incremental name is created. To
edit a node's name, first select it in the Select Node To Edit list, then, on the
right side, click Name and enter the string you wish.

Programmatically Creating Nodes


The branches of a tree view are stored in a property called Nodes. The Nodes
property is an object based on the TreeNodeCollection class. The
TreeNodeCollection class implements the IList, the ICollection, and
the IEnumerable interfaces.

As its name indicates, the Nodes property carries all of the branches of a tree
view. This means that the Nodes property in fact represents a collection. Each
member of this collection is called a node and it is an object based on the
TreeNode class.

At run time, to create a new node, call the TreeNodeCollection.Add()


method which is overloaded with two versions. One of the versions of this
method uses the following syntax:
public virtual TreeNode Add(string text);

This method takes as argument the string that the branch will display. This
method is also the prime candidate to create a root node. Here is an example
of calling it:

C# 3.0 Practical Learning II 801


private void InitializeComponent()
{
Text = "Countries Statistics";
Size = new Size(242, 280);

tvwCountries = new TreeView();


tvwCountries.Location = new Point(12, 12);
tvwCountries.Width = 210;
tvwCountries.Height = 230;

tvwCountries.Nodes.Add("World");

Controls.Add(tvwCountries);
}

This would produce:

Practical Learning: Creating the Root Node

1. Double-click an unoccupied area on the body the form to generate its


Load event

2. To create the first node of the tree, implement the event as follows:
 
private void Central_Load(object sender, EventArgs e)
{
TreeNode nodRoot = tvwAutoParts.Nodes.Add("College
Park Auto-Parts");

for (int i = DateTime.Today.Year + 1; i > 1960; i--)


nodRoot.Nodes.Add(i.ToString());
}

C# 3.0 Practical Learning II 802


3. Execute the application to test the form
 

4. Close the form and return to your programming environment

5. On the main menu, click Project -> Add Class...

6. Set the name to PartDescription and press Enter

7. To create a class that can holds a structured item of a list, change the
class as follows:
 
using System;

namespace CollegeParkAutoParts2
{
public class PartDescription
{
// These members will be used to define a car part
private long ID;
private int yr;

C# 3.0 Practical Learning II 803


private string mk;
private string mdl;
private string cat;
private string name;
private decimal price;

public PartDescription()
{
this.ID = 0;
this.yr = 1960;
this.mk = "";
this.mdl = "";
this.name = "Unknown";
this.price = 0.00M;
}

public PartDescription(long code, int year, string make,


string model, string type,
string desc, decimal UPrice)
{
this.ID = code;
this.yr = year;
this.mk = make;
this.mdl = model;
this.cat = type;
this.name = desc;
this.price = UPrice;
}

public long PartNumber


{
get { return ID; }
set { ID = value; }
}

public int CarYear


{
get { return yr; }
set { yr = value; }
}

public string Make


{
get { return mk; }
set { mk = value; }
}

public string Model


{
get { return mdl; }
set { mdl = value; }
}

public string Category


{
get { return cat; }

C# 3.0 Practical Learning II 804


set { cat = value; }
}

public string PartName


{
get { return name; }
set { name = value; }
}

public decimal UnitPrice


{
get { return (price < 0) ? 0.00M : price; }
set { price = value; }
}

public override string ToString()


{
return this.PartNumber + " " +
this.CarYear.ToString() + " " +
this.Make + " " +
this.Model + " " +
this.Category + " " +
this.PartName + " " +
this.UnitPrice;
}
}
}

A Node and its Children


 

Introduction
The other version of the TreeNodeCollection.Add() method uses the
following syntax:
public virtual int Add(TreeNode node);

This method takes as argument a TreeNode object. In other words, it expects


a complete or semi-complete branch already defined somehow.

The TreeNode class is equipped with various constructors you can use to
instantiate it. Its default constructor allows you to create a node without

C# 3.0 Practical Learning II 805


primarily giving its details. Another TreeNode constructor has the following
syntax:
public TreeNode(string text);

This constructor takes as argument the string that the node will display. Here
is an example of using it and adding its newly create node to the tree view:
private void InitializeComponent()
{
Text = "Countries Statistics";
Size = new Size(242, 280);

tvwCountries = new TreeView();


tvwCountries.Location = new Point(12, 12);
tvwCountries.Width = 210;
tvwCountries.Height = 230;

TreeNode nodElement = new TreeNode("World");


tvwCountries.Nodes.Add(nodElement);

Controls.Add(tvwCountries);
}

We mentioned that the primary characteristic of a node is the text it displays.


The text of a node is stored in a property of the TreeNode class and is called
Text. This allows you either to specify the string of a node or to retrieve it
when needed. Here is an example of setting it:
private void InitializeComponent()
{
Text = "Countries Statistics";
Size = new Size(242, 280);

tvwCountries = new TreeView();


tvwCountries.Location = new Point(12, 12);
tvwCountries.Width = 210;
tvwCountries.Height = 230;

TreeNode nodElement = new TreeNode();


nodElement.Text = "World";
tvwCountries.Nodes.Add(nodElement);

Controls.Add(tvwCountries);
}

Just as we called the TreeNodeCollection.Add() method to create a


branch, you can call it as many times as necessary to create additional
branches. Here is an example:
private void InitializeComponent()
{
Text = "Countries Statistics";
Size = new Size(242, 280);

C# 3.0 Practical Learning II 806


tvwCountries = new TreeView();
tvwCountries.Location = new Point(12, 12);
tvwCountries.Width = 210;
tvwCountries.Height = 230;

tvwCountries.Nodes.Add("World");
tvwCountries.Nodes.Add("Jupiter");
tvwCountries.Nodes.Add("Neptune");
tvwCountries.Nodes.Add("Uranu");

Controls.Add(tvwCountries);
}

This would produce:

Alternatively, if you have many branches to add to the tree, you can first
create them as an array of TreeNode values, then called the
TreeNodeCollection.AddRange() method. The syntax of this method is:

public virtual void AddRange(TreeNode[] nodes);

This method takes as argument an array of TreeNode objects. Here is an


example:
private void InitializeComponent()
{
Text = "Countries Statistics";
Size = new Size(242, 280);

tvwCountries = new TreeView();


tvwCountries.Location = new Point(12, 12);
tvwCountries.Width = 210;
tvwCountries.Height = 230;

TreeNode[] nodPlanets =
{
new TreeNode("World"),
new TreeNode("Jupiter"),
new TreeNode("Neptune"),
new TreeNode("Uranu")
};
tvwCountries.Nodes.AddRange(nodPlanets);

Controls.Add(tvwCountries);
}

C# 3.0 Practical Learning II 807


Creating Child Nodes
At design time and in the TreeNode Editor, to create a child node for an
existing item, first select it in the Select Node To Edit list, then click the Add
Child button. This causes a child node to be created for the selected item. To
edit its name, first click it and change the string in the Label text box.

At run time, to create a child node, first get a reference to the node that will
be used as its parent. One way you can get this reference is to obtain the
returned value of the first version of the TreeNodeCollection.Add()
method. As its syntax indicates, this method returns a TreeNode object.

We have used the default constructor of the TreeNode class and the
constructor that takes as argument a string. The TreeNode class provides
another constructor whose syntax is:
public TreeNode(string text, TreeNode[] children);

The first argument of this method is the string that the new node this
constructor creates will display. The second argument is a collection of the
child nodes of this branch. The collection is passed as an array. Based on this,
you use this constructor to create a new node including its children. After
creating the new node, you can pass it to the TreeNodeCollection.Add()
method as we did earlier. Here is an example:
private void InitializeComponent()
{
Text = "Countries Statistics";
Size = new Size(242, 280);

tvwCountries = new TreeView();


tvwCountries.Location = new Point(12, 12);
tvwCountries.Width = 210;
tvwCountries.Height = 100;

TreeNode[] nodContinents =
{
new TreeNode("Africa"),
new TreeNode("America"),
new TreeNode("Asia"),
new TreeNode("Europe")
};

TreeNode nodWorld = new TreeNode("World",


nodContinents);
tvwCountries.Nodes.Add(nodWorld);

Controls.Add(tvwCountries);
}

This would produce

C# 3.0 Practical Learning II 808


Using the same approach, you can create as many branches and their child
nodes as you wish. Here is an example:
private void InitializeComponent()
{
Text = "Countries Statistics";
Size = new Size(242, 320);

tvwCountries = new TreeView();


tvwCountries.Location = new Point(12, 12);
tvwCountries.Width = 210;
tvwCountries.Height = 270;

// Create a list of some African countries and


// store them in an array named nodAfricans
TreeNode[] nodAfricans = { new TreeNode("Senegal"),
new
TreeNode("Botswana"),
new TreeNode("Ghana"),
new TreeNode("Morocco") };

// Create a list of some American countries and


// store them in an array named nodAmericans
TreeNode[] nodAmericans = { new TreeNode("Canada"),
new
TreeNode("Jamaica"),
new TreeNode("Colombia")};

// Create a list of some European countries and


// store them in an array named nodEuropeans
TreeNode[] nodEuropeans = { new TreeNode("Italy"),
new
TreeNode("Greece"),
new TreeNode("Spain"),
new TreeNode("England") };

// Create a list of continents, independently


TreeNode nodAfrica = new TreeNode("Africa",
nodAfricans);
TreeNode nodAmerica = new TreeNode("America",
nodAmericans);
TreeNode nodAsica = new TreeNode("Asia");
TreeNode nodEurope = new TreeNode("Europe",
nodEuropeans);

C# 3.0 Practical Learning II 809


// Store the list of continents in an array named
nodContinents
TreeNode[] nodContinents = { nodAfrica, nodAmerica,
nodAsica, nodEurope };

// Create a branch named nodWorld and store the list of


// continents as its child
TreeNode nodWorld = new TreeNode("World",
nodContinents);

// Finally, add the nodWorld branch to the tree view


tvwCountries.Nodes.Add(nodWorld);

Controls.Add(tvwCountries);
}

This would produce:

Practical Learning: Creating Child Nodes

1. Access the Central.cs code file and change it 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.Collections;

namespace CollegeParkAutoParts2
{

C# 3.0 Practical Learning II 810


public partial class Central : Form
{
PartDescription[] parts = new PartDescription[100];

public Central()
{
InitializeComponent();
}

private void Central_Load(object sender, EventArgs e)


{
TreeNode nodRoot =
tvwAutoParts.Nodes.Add("College Park Auto-Parts");

// This is simply used to initialize


// the whole array with empty parts
// This is just to make sure that each
// member of the array is defined
for (int n = 0; n < 100; n++)
parts[n] = new PartDescription(0, 1960, "", "",
"", "", 0.00M);

parts[0] = new PartDescription(447093, 2002, "Ford",


"Escort SE L4 2.0", "Engine Electrical",
"Alternator 75amp Remanufactured; w/ 75 Amp",
205.05M);
parts[1] = new PartDescription(203815, 2006,
"Dodge",
"Caravan SE L4 2.4", "Cooling System",
"Radiator Cap", 6.65M);
parts[2] = new PartDescription(293047, 2000,
"Toyota",
"RAV4 2WD/4-DOOR", "Cooling System",
"Thermostat Gasket", 4.95M);
parts[3] = new PartDescription(990468, 2002,
"Honda",
"Civic 1.7 EX 4DR", "Exhaust",
"Bolt & Spring Kit (Manifold outlet, Muffler
Inlet)",
85.75M);
parts[4] = new PartDescription(304158, 1996,
"Buick",
"Regal Custom V6 3.8", "Fuel Injection",
"Fuel Injector", 82.75M);
parts[5] = new PartDescription(807245, 2004,
"Acura",
"MDX 3.5 4WD", "Driveshaft & Axle",
"CV Boot Clamp 7 x 750mm; 1 Large + 1 Small
Clamp",
1.60M);
parts[6] = new PartDescription(203485, 2001, "Ford",
"Taurus LX V6 3.0", "Fuel Injection",
"Oxygen Sensor OE Style 4Wire; Front; 2
Required",
52.65M);
parts[7] = new PartDescription(248759, 1999, "Jeep",

C# 3.0 Practical Learning II 811


"Wrangler Sahara", "Air Intake",
"Air Filter AirSoft Panel", 7.95M);
parts[8] = new PartDescription(202848, 1998,
"Honda",
"Accord 2.3 LX 4DR", "Air Intake",
"Air Filter", 12.55M);
parts[10] = new PartDescription(932759, 2006, "Kia",
"Rio 1.6DOHC16V 4-DR", "Cooling System",
"Thermostat", 14.45M);
parts[11] = new PartDescription(304975, 2000,
"Honda",
"Civic 1.6 EX 4DR", "Suspension",
"Ball Joint; Front Lower; 2 per car", 40.55M);
parts[12] = new PartDescription(208450, 2003,
"Chevrolet",
"Monte Carlo LS V6 3.4", "Fuel Injection",
"Oxygen Sensor OE connector; Rear", 65.55M);
parts[13] = new PartDescription(209480, 2002,
"Ford",
"Focus SE DOHC L4 2.0", "Steering",
"Steering Rack Remanufactured", 170.85M);
parts[9] = new PartDescription(203495, 2004,
"Honda",
"Civic 1.7 EX 4DR", "Climate Control",
"A/C Clutch; OE compressor = Sanden", 184.95M);
parts[14] = new PartDescription(203480, 2007,
"Toyota",
"Corolla", "Air Intake",
"Air Filter", 12.65M);
parts[15] = new PartDescription(109379, 2005,
"Volvo",
"S40 2.5L T5 AWD", "Fuel Delivery",
"Fuel Filter; Early Design; Outer Diameter =
55mm",
30.95M);
parts[16] = new PartDescription(935794, 2002,
"Ford",
"Escape XLS 4WD", "Brake",
"Brake Caliper Remanufactured; Front Right",
65.55M);
parts[17] = new PartDescription(203485, 2006, "BMW",
"325i", "Climate Control",
"AC High Pressure Side Switch",
49.95M);
parts[18] = new PartDescription(204875, 1996,
"Chevrolet",
"Monte Carlo Z34 V6 3.4", "Fuel Delivery",
"Fuel Filter", 8.05M);
parts[19] = new PartDescription(937485, 2007,
"Toyota",
"Camry V6", "Air Intake", "Air Filter", 12.95M);
parts[20] = new PartDescription(294759, 2001,
"Ford",
"Escape XLT 4WD", "Air Intake",
"Air Filter Panel", 7.25M);

C# 3.0 Practical Learning II 812


parts[21] = new PartDescription(297495, 2003,
"Honda",
"Civic 1.7 EX 4DR", "Brake",
"Brake Caliper Reman; w/ ProAct Pads; Front
Right",
82.55M);
parts[22] = new PartDescription(794735, 2006, "BMW",
"325i", "Climate Control",
"Cabin Air/Pollen Filter; With Activated
Carbon",
28.05M);
parts[23] = new PartDescription(937485, 2007,
"Toyota",
"Corolla", "Body Electrical",
"Halogen SilverStar; 12V 65W; inner-high beam",
22.85M);
parts[24] = new PartDescription(492745, 2005,
"Ford",
"Focus ZX3 L4 2.0", "Air Intake",
"Fuel Injection Perf Kit", 342.95M);
parts[25] = new PartDescription(937005, 2004,
"Acura",
"MDX 3.5 4WD", "Driveshaft & Axle",
"CV Boot Clamp 7 x 750mm; For Large End of Boot;
inner boot",
1.60M);
parts[26] = new PartDescription(293749, 2004,
"Acura",
"MDX 3.5 4WD", "Driveshaft & Axle",
"Axle Nut 24mm x 1;5; rear ",
2.35M);
parts[27] = new PartDescription(920495, 2006, "BMW",
"325i", "Climate Control",
"Adjustable Telescoping Mirror", 7.95M);
parts[28] = new PartDescription(204075, 2004,
"Acura",
"MDX 3.5 4WD", "Driveshaft & Axle",
"Wheel Bearing; Rear; 1 per wheel",
70.15M);
parts[29] = new PartDescription(979304, 2000,
"Toyota",
"RAV4 2WD/4-DOOR", "Cooling System",
"Thermostat Housing", 20.95M);
parts[30] = new PartDescription(300456, 2004,
"Acura",
"MDX 3.5 4WD", "Driveshaft & Axle",
"Wheel Bearing; Front; 1 per wheel",
66.65M);
parts[31] = new PartDescription(404860, 2001,
"Ford",
"Taurus LX V6 3.0", "Suspension",
"Shock Absorber GR2; Rear; Wagon only",
39.40M);
parts[32] = new PartDescription(585688, 2007,
"Buick",
"Lacrosse CXS V6 3.6", "Brake",

C# 3.0 Practical Learning II 813


"Climate Control", 10.65M);
parts[33] = new PartDescription(739759, 2001,
"Ford",
"Taurus LX V6 3.0", "Suspension",
"Shock Absorber GasaJust; Rear; Wagon only",
30.95M);
parts[34] = new PartDescription(927495, 2005,
"Volvo",
"S40 2.5L T5 AWD", "Engine Mechanical",
"Timing Belt Idler Pulley Original Equipment
INA",
65.55M);
parts[40] = new PartDescription(979374, 2000,
"Toyota",
"RAV4 2WD/4-DOOR", "Cooling System",
"Thermostat Gasket", 4.95M);
parts[35] = new PartDescription(542347, 2007,
"Buick",
"Lacrosse CXS V6 3.6", "Brake",
"Brake Pad Set ProACT Ceramic w/Shims; Front",
80.05M);
parts[36] = new PartDescription(683064, 2000,
"Toyota",
"RAV4 2WD/4-DOOR", "Cooling System",
"Radiator Hose; Upper", 103.75M);
parts[37] = new PartDescription(248759, 1999,
"Jeep",
"Wrangler Sahara", "Air Intake",
"Air Filter", 50.95M);
parts[38] = new PartDescription(973974, 2007,
"Toyota",
"Corolla", "Air Intake",
"Air Mass Meter; W/o Housing; Meter/sensor
only",
134.95M);
parts[39] = new PartDescription(285800, 2001,
"Ford",
"Escape XLT 4WD", "Transmission",
"AT Filter", 34.95M);
parts[41] = new PartDescription(207495, 2007,
"Toyota",
"Corolla", "Body Electrical",
"Headlight Bulb; 12V 65W; inner-high beam",
9.35M);
parts[42] = new PartDescription(566676, 2000,
"Toyota",
"RAV4 2WD/4-DOOR", "Cooling System",
"Auxiliary Fan Switch", 42.95M);
parts[43] = new PartDescription(304950, 2007,
"Toyota",
"Corolla", "Body Electrical",
"Headlight Bulb; 12V 51W; outer", 7.85M);
parts[44] = new PartDescription(797394, 2000,
"Toyota",
"RAV4 2WD/4-DOOR", "Cooling System",
"Water Flange Gasket", 0.85M);

C# 3.0 Practical Learning II 814


parts[45] = new PartDescription(910203, 2007,
"Buick",
"Lacrosse CXS V6 3.6", "Suspension",
"Strut Mount Inc; Sleeve; Rear Right", 80.85M);
parts[46] = new PartDescription(790794, 2000,
"Toyota",
"RAV4 2WD/4-DOOR", "Cooling System",
"Radiator Hose; Lower", 9.45M);
parts[47] = new PartDescription(970394, 2007,
"Buick",
"Lacrosse CXS V6 3.6", "Suspension",
"Coil Spring Insulator; Front Lower",
14.55M);
parts[48] = new PartDescription(290840, 2005,
"Volvo",
"S40 2.5L T5 AWD", "Engine Mechanical",
"Rod Bearing Set 1 per Rod; Standard; Reqs. 5-
per Engine",
26.95M);
parts[49] = new PartDescription(209704, 2007,
"Toyota",
"Corolla", "Body Electrical",
"Wiper Blade Excel+; Front Right", 7.25M);
parts[50] = new PartDescription(200368, 2000,
"Toyota",
"RAV4 2WD/4-DOOR", "Cooling System",
"Radiator Drain Plug incl; gasket", 3.15M);
parts[51] = new PartDescription(200970, 2005,
"Volvo",
"S40 2.5L T5 AWD", "Engine Mechanical",
"Reference Sensor; Flywheel Engine Speed",
62.05M);
parts[52] = new PartDescription(542347, 2007,
"Buick",
"Lacrosse CXS V6 3.6", "Air Intake",
"Air Filter", 50.25M);
parts[53] = new PartDescription(927045, 2001,
"Ford",
"Escape XLT 4WD", "Air Intake",
"Air Filter", 62.95M);
parts[54] = new PartDescription(990659, 2000,
"Toyota",
"RAV4 2WD/4-DOOR", "Cooling System",
"Radiator OE Plastic tank", 136.85M);
parts[55] = new PartDescription(440574, 2007,
"Buick",
"Lacrosse CXS V6 3.6", "Suspension",
"Strut Mount Inc; Sleeve; Rear Left",
80.80M);

// Showing the years nodes


for (int years = DateTime.Today.Year + 1; years >
1960; years--)
nodRoot.Nodes.Add(years.ToString());

// Showing the makes nodes

C# 3.0 Practical Learning II 815


foreach (TreeNode nodYear in nodRoot.Nodes)
{
ArrayList lstMakes = new ArrayList();

foreach (PartDescription part in parts)


{
if (nodYear.Text == part.CarYear.ToString())
{
if (!lstMakes.Contains(part.Make))
lstMakes.Add(part.Make);
}
}

foreach (string strMake in lstMakes)


nodYear.Nodes.Add(strMake);
}

// Showing the models nodes


foreach (TreeNode nodYear in nodRoot.Nodes)
{
foreach (TreeNode nodMake in nodYear.Nodes)
{
ArrayList lstModels = new ArrayList();

foreach (PartDescription part in parts)


{

if ((nodYear.Text ==
part.CarYear.ToString()) &&
(nodMake.Text == part.Make))
{
if (!lstModels.Contains(part.Model))
lstModels.Add(part.Model);

}
}

foreach (string strModel in lstModels)


nodMake.Nodes.Add(strModel);
}
}

// Showing the categories nodes


foreach (TreeNode nodYear in nodRoot.Nodes)
{
foreach (TreeNode nodMake in nodYear.Nodes)
{
foreach (TreeNode nodModel in nodMake.Nodes)
{
ArrayList lstCategories = new
ArrayList();

foreach (PartDescription part in parts)


{

C# 3.0 Practical Learning II 816


if ((nodYear.Text ==
part.CarYear.ToString()) &&
(nodMake.Text == part.Make) &&
(nodModel.Text == part.Model))
{
if (!
lstCategories.Contains(part.Category))

lstCategories.Add(part.Category);
}
}

foreach (string strCategory in


lstCategories)
nodModel.Nodes.Add(strCategory);
}
}
}
}
}
}

2. Save all

The Number of Child Nodes


The number of nodes in the TreeNode objects is stored in the
TreeNodeCollection.Count property. To get the current number of nodes
in the tree view, you can call the TreeView.GetNodeCount() method. Its
syntax is:
public int GetNodeCount(bool includeSubTrees);

Here is an example:
private void InitializeComponent()
{
Text = "Countries Statistics";
Size = new Size(242, 320);

tvwCountries = new TreeView();


tvwCountries.Location = new Point(12, 12);
tvwCountries.Width = 210;
tvwCountries.Height = 270;

// Create a list of some African countries and


// store them in an array named nodAfricans
TreeNode[] nodAfricans = { new TreeNode("Senegal"),
new
TreeNode("Botswana"),
new TreeNode("Ghana"),
new TreeNode("Morocco") };

. . . No Change

C# 3.0 Practical Learning II 817


Controls.Add(tvwCountries);

int count = tvwCountries.GetNodeCount(true);


Text = count.ToString();
}

This would produce:

If you create a node and add it to a branch that already contains another
node, the new node is referred to as a sibling to the existing child node.

The Nodes of a Node


In our introduction, we saw that a node, any node, could have as many
nodes as you judge necessary. To support this, the TreeNode class is
equipped with a property called Nodes, which, like that of the TreeView
class, is based on the TreeNodeCollection class. This allows you to refer to
the list of children of the node that this Nodes property belongs to. With this
information, you can further create or manipulate child nodes of any node as
you wish.

Node Selection
Besides looking at a node, probably the primary action a user performs on a
tree is to select an item. To select a node in the tree, the user can click it. To
programmatically select a node, assign its reference to the
TreeView.SelectedNode property. Here is an example:

private void InitializeComponent()


{
Text = "Countries Statistics";
Size = new Size(242, 320);

tvwCountries = new TreeView();


tvwCountries.Location = new Point(12, 12);
tvwCountries.Width = 210;
tvwCountries.Height = 100;

TreeNode nodAfrica = new TreeNode("Africa");


TreeNode nodAmerica = new TreeNode("America");
TreeNode nodEurope = new TreeNode("Europe");
TreeNode[] nodContinents = { nodAfrica, nodAmerica,
nodEurope };

C# 3.0 Practical Learning II 818


TreeNode nodWorld = new TreeNode("World",
nodContinents);
tvwCountries.Nodes.Add(nodWorld);

tvwCountries.SelectedNode = nodAmerica;

Controls.Add(tvwCountries);
}

After selecting a node, the tree view indicates the item selected by
highlighting it. In the following picture, the America node is selected:

To programmatically find out what item is selected in the tree, get the value
of the TreeView.SelectedNode Boolean property. If no node is selected,
this property produces null. Alternatively, you can check the value of a node's
TreeNode.IsSelected Boolean property to find out if it is currently selected.

Node Edition
After locating a node, the user may want to change its text. To change the
string of a node, it must be put to edit mode. To do this, you can call the
TreeNode.BeginEdit() method. Its syntax is:

public void BeginEdit();

When a node is in edit mode, the caret blinks in its edit box section. The user
can then type a new string or edit the existing string. After setting the (new)
string, the user can press Enter or may click somewhere. At this time, you
need to indicate that the user has finished this operation. To do this, you can
call the TreeNode.EndEdit() method. Its syntax is:
public void EndEdit(bool cancel);

Just before this method, you can check the content of the string that was
added or edited. This allows you to accept or reject the change. The
argument to the EndEdit() method allows you to validate or cancel the
editing action.

Node Location

C# 3.0 Practical Learning II 819


As mentioned already, the nodes of a tree view are stored in a collection of
type TreeNodeCollection. Every time you create a new node, it occupies a
position inside the tree. Each node is represented by the Item indexed
property of this collection. The first node of the tree has an index of 0.

When you call the TreeNodeCollection.Add() method to create a node,


the new branch is added at the end of the list of its siblings. If you want, you
can add a new child somewhere in the tree. To do this, you would call the
TreeNodeCollection.Insert() method. Its syntax is:

public virtual void Insert(int index, TreeNode node);

The first argument to this method is the index that the new node will occupy
when created. The second argument is a reference to the new node to be
created. Here is an example of using it:
private void InitializeComponent()
{
Text = "Countries Statistics";
Size = new Size(242, 320);

tvwCountries = new TreeView();


tvwCountries.Location = new Point(12, 12);
tvwCountries.Width = 210;
tvwCountries.Height = 100;

TreeNode[] nodContinents =
{
new TreeNode("Africa"),
new TreeNode("America"),
new TreeNode("Asia"),
new TreeNode("Europe")
};

TreeNode nodWorld = new TreeNode("World",


nodContinents);
tvwCountries.Nodes.Add(nodWorld);

tvwCountries.Nodes.Insert(1, new TreeNode("Neptune"));

Controls.Add(tvwCountries);
}

This would produce:

C# 3.0 Practical Learning II 820


Another technique you can use to locate a node consists of using some
coordinates. To do this, you can call the TreeView.GetNodeAt() method
that is overloaded with two versions whose syntaxes are:
public TreeNode GetNodeAt(Point pt);
public TreeNode GetNodeAt(int x, int y);

To use this method, you must know either the Point location or the x and y
coordinates of the node. If you provide valid arguments to this method, it
returns a reference to the TreeNode located at the argument. Here is an
example:
private void InitializeComponent()
{
Text = "Countries Statistics";
Size = new Size(242, 320);

tvwCountries = new TreeView();


tvwCountries.Location = new Point(12, 12);
tvwCountries.Width = 210;
tvwCountries.Height = 100;

TreeNode[] nodContinents =
{
new TreeNode("Africa"),
new TreeNode("America"),
new TreeNode("Asia"),
new TreeNode("Europe")
};

TreeNode nodWorld = new TreeNode("World",


nodContinents);
tvwCountries.Nodes.Add(nodWorld);

tvwCountries.ExpandAll();
TreeNode nodBranch = tvwCountries.GetNodeAt(22, 48);

Controls.Add(tvwCountries);
Text = nodBranch.Text;
}

This would produce:

After creating a tree, to get a reference to the first child node, you can
retrieve the TreeNode.FirstNode property. You would use code as follows:

C# 3.0 Practical Learning II 821


private void InitializeComponent()
{
Text = "Countries Statistics";
Size = new Size(242, 320);

tvwCountries = new TreeView();


tvwCountries.Location = new Point(12, 12);
tvwCountries.Width = 210;
tvwCountries.Height = 100;

TreeNode[] nodContinents = { new TreeNode("Africa"),


new TreeNode("America"),
new TreeNode("Asia"),
new TreeNode("Europe") };

TreeNode nodWorld = new TreeNode("World",


nodContinents);
tvwCountries.Nodes.Add(nodWorld);

TreeNode nodFirst = tvwCountries.Nodes[0].FirstNode;


Controls.Add(tvwCountries);

Text = nodFirst.Text;
}

To get a reference to the last child node, retrieve the TreeNode.LastNode


property. You would use code as follows:
TreeNode nodLast = tvwCountries.Nodes[0].LastNode;
Text = nodLast.Text;

To get a reference to the sibling above a node, if any, you can retrieve its
TreeNode.PrevNode property. To get a reference to the sibling below a
node, if any, you can retrieve its TreeNode.NextNode property.

To find whether a tree view contains a certain node, you can call the
TreeNodeCollection.Contains() method. Its syntax is:

public bool Contains(TreeNode node);

This method expects as argument a reference to the node to look for. If the
tree contains that node, the method returns true. If the node is not found,
this method returns false.

Practical Learning: Using the Selected Node

1. On the form, click the tree view

C# 3.0 Practical Learning II 822


2. In the Properties window, click the Events button and double-click
NodeMouseClick

3. Implement the event as follows:


 
private void tvwAutoParts_NodeMouseClick(object sender,
TreeNodeMouseClickEventArgs e)
{
TreeNode nodClicked = e.Node;

if( nodClicked.Level == 4 )
lvwAutoParts.Items.Clear();

try
{
try
{
foreach (PartDescription part in parts)
{
if ((part.Category == nodClicked.Text)
&&
(part.Model ==
nodClicked.Parent.Text) &&
(part.Make ==
nodClicked.Parent.Parent.Text) &&
(part.CarYear.ToString() ==
nodClicked.Parent.Parent.Parent.Text))
{
ListViewItem lviAutoPart = new
ListViewItem(part.PartNumber.ToString());

lviAutoPart.SubItems.Add(part.PartName);

lviAutoPart.SubItems.Add(part.UnitPrice.ToString());
lvwAutoParts.Items.Add(lviAutoPart);
}
}
}
catch (NullReferenceException)
{
}
}
catch (NullReferenceException)
{
}
}

4. Return to the form and click the list view

5. In the Properties window, click the Events button and, in the Events
section, double-click DoubleClick

C# 3.0 Practical Learning II 823


6. Implement the event as follows:
 
internal void CalculateOrder()
{
// Calculate the current total order and update the
order
decimal subTotal1 = 0.00M, subTotal2 = 0.00M,
subTotal3 = 0.00M,
subTotal4 = 0.00M, subTotal5 = 0.00M,
subTotal6 = 0.00M;
decimal orderTotal = 0.00M;

// Retrieve the value of each sub total


try
{
subTotal1 =
decimal.Parse(this.txtSubTotal1.Text);
}
catch (FormatException)
{
MessageBox.Show("Invalid Value");
}

try
{
subTotal2 =
decimal.Parse(this.txtSubTotal2.Text);
}
catch (FormatException)
{
MessageBox.Show("Invalid Value");
}

try
{
subTotal3 =
decimal.Parse(this.txtSubTotal3.Text);
}
catch (FormatException)
{
MessageBox.Show("Invalid Value");
}

try
{
subTotal4 =
decimal.Parse(this.txtSubTotal4.Text);
}
catch (FormatException)
{
MessageBox.Show("Invalid Value");
}

try
{

C# 3.0 Practical Learning II 824


subTotal5 =
decimal.Parse(this.txtSubTotal5.Text);
}
catch (FormatException)
{
MessageBox.Show("Invalid Value");
}

try
{
subTotal6 =
decimal.Parse(this.txtSubTotal6.Text);
}
catch (FormatException)
{
MessageBox.Show("Invalid Value");
}

// Calculate the total value of the sub totals


orderTotal = subTotal1 + subTotal2 + subTotal3 +
subTotal4 + subTotal5 + subTotal6;

// Display the total order in the appropriate text


box
this.txtTotalOrder.Text = orderTotal.ToString();
}

private void lvwAutoParts_DoubleClick(object sender, EventArgs


e)
{
ListViewItem lviAutoPart =
lvwAutoParts.SelectedItems[0];

if (lvwAutoParts.SelectedItems.Count == 0 ||
lvwAutoParts.SelectedItems.Count > 1)
return;

if (txtPartNumber1.Text == "")
{
txtPartNumber1.Text = lviAutoPart.Text;
txtPartName1.Text =
lviAutoPart.SubItems[1].Text;
txtUnitPrice1.Text =
lviAutoPart.SubItems[2].Text;

txtQuantity1.Text = "1";
txtSubTotal1.Text =
lviAutoPart.SubItems[2].Text;

txtQuantity1.Focus();
}// If the previous Part # text box is not empty,
then use the next one
else if (txtPartNumber2.Text == "")
{
txtPartNumber2.Text = lviAutoPart.Text;

C# 3.0 Practical Learning II 825


txtPartName2.Text =
lviAutoPart.SubItems[1].Text;
txtUnitPrice2.Text =
lviAutoPart.SubItems[2].Text;

txtQuantity2.Text = "1";
txtSubTotal2.Text = txtUnitPrice2.Text;
txtQuantity2.Focus();
}
else if (txtPartNumber3.Text == "")
{
txtPartNumber3.Text = lviAutoPart.Text;
txtPartName3.Text =
lviAutoPart.SubItems[1].Text;
txtUnitPrice3.Text =
lviAutoPart.SubItems[2].Text;

txtQuantity3.Text = "1";
txtSubTotal3.Text = txtUnitPrice3.Text;
txtQuantity3.Focus();
}
else if (txtPartNumber4.Text == "")
{
txtPartNumber4.Text = lviAutoPart.Text;
txtPartName4.Text =
lviAutoPart.SubItems[1].Text;
txtUnitPrice4.Text =
lviAutoPart.SubItems[2].Text;

txtQuantity4.Text = "1";
txtSubTotal4.Text = txtUnitPrice4.Text;
txtQuantity4.Focus();
}
else if (txtPartNumber5.Text == "")
{
txtPartNumber5.Text = lviAutoPart.Text;
txtPartName5.Text =
lviAutoPart.SubItems[1].Text;
txtUnitPrice5.Text =
lviAutoPart.SubItems[2].Text;

txtQuantity5.Text = "1";
txtSubTotal5.Text = txtUnitPrice5.Text;
txtQuantity5.Focus();
}
else if (txtPartNumber6.Text == "")
{
txtPartNumber6.Text = lviAutoPart.Text;
txtPartName6.Text =
lviAutoPart.SubItems[1].Text;
txtUnitPrice6.Text =
lviAutoPart.SubItems[2].Text;

txtQuantity6.Text = "1";
txtSubTotal6.Text = txtUnitPrice6.Text;
txtQuantity6.Focus();

C# 3.0 Practical Learning II 826


} // If all Part # text boxes are filled, don't do
anything
else
return;

CalculateOrder();
}

7. Return to the form

8. On the form, click the first text box under Qty

9. In the Events section of the Properties window, double-click the Leave


field

10. Implement the event as follows:


 
private void txtQuantity1_Leave(object sender, EventArgs e)
{
int qty = 0;
decimal unitPrice = 0.00M, subTotal = 0.00M;

// Get the quantity of the current item


try
{
qty = int.Parse(this.txtQuantity1.Text);
}
catch (FormatException)
{
MessageBox.Show("Invalid Value");
}

// Get the unit price of the current item


try
{
unitPrice =
decimal.Parse(this.txtUnitPrice1.Text);
}
catch (FormatException)
{
MessageBox.Show("Invalid Value");
}

// Calculate the current sub total


subTotal = qty * unitPrice;

// Display the new sub total in the corresponding


text box
this.txtSubTotal1.Text = subTotal.ToString();
// Update the order
CalculateOrder();
}

11. Return to the form and click the second text box under Qty

C# 3.0 Practical Learning II 827


12. In the Events section of the Properties window, double-click the Leave
field and implement the event as follows:
 
private void txtQuantity2_Leave(object sender, EventArgs e)
{
int qty = 0;
decimal unitPrice = 0.00M, subTotal = 0.00M;

try
{
qty = int.Parse(this.txtQuantity2.Text);
}
catch (FormatException)
{
MessageBox.Show("Invalid Value");
}

try
{
unitPrice =
decimal.Parse(this.txtUnitPrice2.Text);
}
catch (FormatException)
{
MessageBox.Show("Invalid Value");
}

subTotal = qty * unitPrice;


this.txtSubTotal2.Text = subTotal.ToString();

CalculateOrder();
}

13. Return to the form and click the third text box under Qty

14. In the Events section of the Properties window, double-click the Leave
field and implement the event as follows:
 
private void txtQuantity3_Leave(object sender, EventArgs e)
{
int qty = 0;
decimal unitPrice = 0.00M, subTotal = 0.00M;

try
{
qty = int.Parse(this.txtQuantity3.Text);
}
catch (FormatException)
{
MessageBox.Show("Invalid Value");
}

try

C# 3.0 Practical Learning II 828


{
unitPrice =
decimal.Parse(this.txtUnitPrice3.Text);
}
catch (FormatException)
{
MessageBox.Show("Invalid Value");
}

subTotal = qty * unitPrice;


this.txtSubTotal3.Text = subTotal.ToString();

CalculateOrder();
}

15. Return to the form and click the fourth text box under Qty

16. In the Events section of the Properties window, double-click the Leave
field and implement the event as follows:
 
private void txtQuantity4_Leave(object sender, EventArgs e)
{
int qty = 0;
decimal unitPrice = 0.00M, subTotal = 0.00M;

try
{
qty = int.Parse(this.txtQuantity4.Text);
}
catch (FormatException)
{
MessageBox.Show("Invalid Value");
}

try
{
unitPrice =
decimal.Parse(this.txtUnitPrice4.Text);
}
catch (FormatException)
{
MessageBox.Show("Invalid Value");
}

subTotal = qty * unitPrice;


this.txtSubTotal4.Text = subTotal.ToString();

CalculateOrder();
}

17. Return to the form and click the fifth text box under Qty

C# 3.0 Practical Learning II 829


18. In the Events section of the Properties window, double-click the Leave
field and implement the event as follows:
 
private void txtQuantity5_Leave(object sender, EventArgs e)
{
int qty = 0;
decimal unitPrice = 0.00M, subTotal = 0.00M;

try
{
qty = int.Parse(this.txtQuantity5.Text);
}
catch (FormatException)
{
MessageBox.Show("Invalid Value");
}

try
{
unitPrice =
decimal.Parse(this.txtUnitPrice5.Text);
}
catch (FormatException)
{
MessageBox.Show("Invalid Value");
}

subTotal = qty * unitPrice;


this.txtSubTotal5.Text = subTotal.ToString();

CalculateOrder();
}

19. Return to the form and click the sixth text box under Qty

20. In the Events section of the Properties window, double-click the Leave
field and implement the event as follows:
 
private void txtQuantity6_Leave(object sender, EventArgs e)
{
int qty = 0;
decimal unitPrice = 0.00M, subTotal = 0.00M;

try
{
qty = int.Parse(this.txtQuantity6.Text);
}
catch (FormatException)
{
MessageBox.Show("Invalid Value");
}

try

C# 3.0 Practical Learning II 830


{
unitPrice =
decimal.Parse(this.txtUnitPrice6.Text);
}
catch (FormatException)
{
MessageBox.Show("Invalid Value");
}

subTotal = qty * unitPrice;


this.txtSubTotal6.Text = subTotal.ToString();

CalculateOrder();
}

21. Return to the form

22. Double-click the first Remove button and implement its event as follows:
 
private void btnRemove1_Click(object sender, EventArgs e)
{
txtPartNumber1.Text = "";
txtPartName1.Text = "";
txtUnitPrice1.Text = "0.00";
txtQuantity1.Text = "0";
txtSubTotal1.Text = "0.00";

CalculateOrder();
}

23. Return to the form

24. Double-click the second Remove button and implement its event as
follows:
 
private void btnRemove2_Click(object sender, EventArgs e)
{
txtPartNumber2.Text = "";
txtPartName2.Text = "";
txtUnitPrice2.Text = "0.00";
txtQuantity2.Text = "0";
txtSubTotal2.Text = "0.00";

CalculateOrder();
}

25. Return to the form

26. Double-click the third Remove button and implement its event as
follows:
 
private void btnRemove3_Click(object sender, EventArgs e)
{

C# 3.0 Practical Learning II 831


txtPartNumber3.Text = "";
txtPartName3.Text = "";
txtUnitPrice3.Text = "0.00";
txtQuantity3.Text = "0";
txtSubTotal3.Text = "0.00";

CalculateOrder();
}

27. Return to the form

28. Double-click the fourth Remove button and implement its event as
follows:
 
private void btnRemove4_Click(object sender, EventArgs e)
{
txtPartNumber4.Text = "";
txtPartName4.Text = "";
txtUnitPrice4.Text = "0.00";
txtQuantity4.Text = "0";
txtSubTotal4.Text = "0.00";

CalculateOrder();
}

29. Return to the form

30. Double-click the fifth Remove button and implement its event as follows:
 
private void btnRemove5_Click(object sender, EventArgs e)
{
txtPartNumber5.Text = "";
txtPartName5.Text = "";
txtUnitPrice5.Text = "0.00";
txtQuantity5.Text = "0";
txtSubTotal5.Text = "0.00";

CalculateOrder();
}

31. Return to the form

32. Double-click the sixth Remove button and implement its event as
follows:
 
private void btnRemove6_Click(object sender, EventArgs e)
{
txtPartNumber6.Text = "";
txtPartName6.Text = "";
txtUnitPrice6.Text = "0.00";
txtQuantity6.Text = "0";
txtSubTotal6.Text = "0.00";

C# 3.0 Practical Learning II 832


CalculateOrder();
}

33. Return to the form

34. Double-click the Close button and implement its Click event as follows:
 
private void btnClose_Click(object sender, EventArgs e)
{
Close();
}

35. Execute the application to test it


 

36. After using it, close the form

Deleting Nodes

C# 3.0 Practical Learning II 833


When a tree contains a few nodes, the user may want to delete some of
them, for any reason. To delete a node, you can call the
TreeNodeCollection.Remove() method. Its syntax is:

public void Remove(TreeNode node);

This method expects a reference to the node you want to delete. Another
solution you can use would consist of locating the node by its index. To do
this, you would call the TreeNodeCollection.RemoveAt() method. Its
syntax is:
public virtual void RemoveAt(int index);

When calling this method, pass the index of the node to be deleted. If you
are already at that node and you want to remove it, you can call the
TreeNode.Remove() method. Its syntax is:

public void Remove();

One of the characteristics of a tree in the real world is that, if you cut a
branch, the branches attached to it and their leaves are cut too. In the same
way, if you call any of these Remove() or RemoveAt() methods to delete a
node, its children, if any, would be deleted too.

To remove all nodes of a tree view, you can call the


TreeNodeCollection.Clear() method. Its syntax is:

public virtual void Clear();

This method is used to get rid of all nodes of a tree.

Characteristics of a Tree View


 

The Path to a Node


After a node has been added to a tree, it holds a position relative to its parent
and its existence depends on that parent. To keep track of its "ancestry",
each node has a path that can be used to identify its parent and its grand-
parent(s), if any. To know the path of a node from itself to the root, you can
access its TreeNode.FullPath property. This property produces a string
made of sections separated by a specific character identified as the
TreeView.PathSeparator property.

C# 3.0 Practical Learning II 834


By default, this character is the backslash, following the conventions of the
operating system. If you want to use a different character or string, assign it
to the PathSeparator property. To know what character or string a tree
view is using as the separator, you can retrieve the value of its
PathSeparator property.

Hot Tracking
In order to select an item, the user must click it or navigate to it using the
keyboard. Alternatively, if you want the items to be underlined when the
mouse passes over them, set to true the TreeView.HotTracking Boolean
property. Its default value is false. Here is an example:
private void InitializeComponent()
{
Text = "Countries Statistics";
Size = new Size(242, 320);

tvwCountries = new TreeView();


tvwCountries.Location = new Point(12, 12);
tvwCountries.Width = 210;
tvwCountries.Height = 100;

tvwCountries.HotTracking = true;

Controls.Add(tvwCountries);

TreeNode[] nodContinents = { new TreeNode("Africa"),


new TreeNode("America"),
new TreeNode("Asia"),
new TreeNode("Europe") };

TreeNode nodWorld = new TreeNode("World",


nodContinents);
tvwCountries.Nodes.Add(nodWorld);
}

This would produce:

The Intermediary Lines of Related Nodes


As mentioned already, a tree view appears as a list of items arranged like a
tree. This implies a relationship of parent-child among the items in the

C# 3.0 Practical Learning II 835


control. To indicate this relationship between two nodes, a line is drawn from
one to another. Based on this, a line from a node on top of another node
under it indicates that the one on top is the parent to the one under it.

The presence or absence of the lines among related nodes is controlled by


the TreeView.ShowLines Boolean property. By default, this property is set to
true (in the .NET Framework, some other libraries have it set by default to
false). If this property is set to false, the lines between the nodes would not
display. Here is an example:
private void InitializeComponent()
{
Text = "Countries Statistics";
Size = new Size(242, 320);

tvwCountries = new TreeView();


tvwCountries.Location = new Point(12, 12);
tvwCountries.Width = 210;
tvwCountries.Height = 100;

tvwCountries.ShowLines = false;

TreeNode[] nodContinents = { new TreeNode("Africa"),


new TreeNode("America"),
new TreeNode("Asia"),
new TreeNode("Europe") };

TreeNode nodWorld = new TreeNode("World",


nodContinents);
tvwCountries.Nodes.Add(nodWorld);

Controls.Add(tvwCountries);
}

This would produce:

The Root Lines


If you create a tree that has more than one root, a line is drawn among those
root nodes. Here is an example:

C# 3.0 Practical Learning II 836


The presence or absence of this type of line is controlled by the
TreeView.ShowRootLines Boolean property.

Node Indentation
Indentation is the ability for a child node to be aligned to the right with
regards to its parent. The general distance from the left border of the parent
to the left border of the child is partially controlled by the TreeView.Indent
property which is an integer. If the default distance doesn't suit you, you can
change it by assigning a positive number to the control's Indent property.

Full Row Selection


When the user clicks an item, that node becomes highlighted for the length of
its string. If you want, you can show the highlighting on the selected node
but from the left to the right borders of the tree view. To do this, you can set
the TreeView.FullRowSelect Boolean property to true. Its default value is
false. For the TreeView.FullRowSelect property to work, the ShowLines
property must be set to false. Here is an example:
private void InitializeComponent()
{
Text = "Countries Statistics";
Size = new Size(242, 320);

tvwCountries = new TreeView();


tvwCountries.Location = new Point(12, 12);
tvwCountries.Width = 210;
tvwCountries.Height = 100;

tvwCountries.HotTracking = true;
tvwCountries.ShowLines = false;
tvwCountries.FullRowSelect = true;

TreeNode[] nodContinents = { new TreeNode("Africa"),


new TreeNode("America"),
new TreeNode("Asia"),
new TreeNode("Europe") };

TreeNode nodWorld = new TreeNode("World",


nodContinents);
tvwCountries.Nodes.Add(nodWorld);

C# 3.0 Practical Learning II 837


Controls.Add(tvwCountries);
}

This would produce:

Hiding Selection After Losing Focus


We saw that, to select an item, the user can click it. If the user clicks another
control, the node that was selected in the tree view loses its highlighting
because the control has lost focus. When the focus moves to another control,
if you want the selected node of the tree view to preserve its highlighting, set
to false the TreeView.HideSelection Boolean property. Its default value is
true.

The + and - Buttons


At this time, we have seen that some nodes have children and some don't.
When a node has at least one child, the node indicates this by displaying a +
button. If the user clicks the + button, the node expands, displays a list of its
children, and the button becomes -. The presence or absence of the + and -
buttons is controlled by the TreeView.ShowPlusMinus Boolean property. By
default, this property is set to true. If you don't want the parent nodes to
display the + or - button, set this property to false.

Expanding and Collapsing Tree Nodes


When a node displays a + button and the user clicks that button, the node
displays its child(ren). This action is referred to as expanding the node. To
programmatically expand a node, call its TreeNode.Expand() method. Its
syntax is:
public void Expand();

This method only expands the node that calls it but if its children have their
own children, they are not expanded.  To expand a node and its children that
have nodes, you can call its TreeNode.ExpandAll() method. Its syntax is:
public void ExpandAll();

To find out if a
node is expanded, check the value of its
TreeNode.IsExpanded property.

C# 3.0 Practical Learning II 838


To expand other nodes of the tree view, the user can continue clicking each
node that has a + button as necessary. To programmatically expand all nodes
of a tree view, call its TreeView.ExpandAll() method. Its syntax is:
public void ExpandAll();

If a node is displaying a - button, it indicates that it is showing the list of its


children. To hide the list, the user can click the - button. This action is
referred to as collapsing the node. To programmatically collapse a node, call
its TreeNode.Collapse() method whose syntax is:
public void Collapse();

The user can do this for each node that is expanded. To programmatically
collapse all nodes of a tree view, call its TreeView.CollapseAll() method.
Its syntax is:
public void CollapseAll();

Tree Nodes and Check Boxes


Besides the strings (and some small pictures as we will see later), the nodes
of a tree view can display a check box on their left side. The presence or
absence of the check box is controlled by the CheckBoxes Boolean property
whose default value is false. If you want to display the check boxes, set this
property to true. Here is an example:
private void InitializeComponent()
{
Text = "Countries Statistics";
Size = new Size(242, 320);

tvwCountries = new TreeView();


tvwCountries.Location = new Point(12, 12);
tvwCountries.Width = 210;
tvwCountries.Height = 100;

tvwCountries.CheckBoxes = true;

TreeNode[] nodContinents = { new TreeNode("Africa"),


new TreeNode("America"),
new TreeNode("Asia"),
new TreeNode("Europe") };

TreeNode nodWorld = new TreeNode("World",


nodContinents);
tvwCountries.Nodes.Add(nodWorld);

Controls.Add(tvwCountries);
}

This would produce:

C# 3.0 Practical Learning II 839


If you equip the nodes with check boxes, the user can click an item to select
it independently of the check box. The user can also click the check box,
which would place a check mark in the box. To programmatically check the
box, you can assign a true value to the node's Checked property.

When a check mark has been placed in a node's check box, the tree view
fires an AfterCheck event, which is handled by the TreeViewEventHandler
delegate. The AfterCheck event is carried by the TreeViewEventArgs class.
One of properties of this class is called Action, which specifies why or how
the event occurred. The Action property is in fact a value based on the
TreeViewAction enumerator. Its members are:

ByKeyboard: This indicates that the event was fired by pressing a key

ByMouse: This indicates that the event was fired based on an action on the
mouse

Collapse: This indicates that event was fired when the tree collapsed

Expand: This indicates that the event was fired when the tree expanded

Unknown: None of the above reasons caused the event, but the event was
fired

The other property of the TreeViewEventArgs class is called Node. This


member is of type TreeNode. It carries a reference to the node that fired the
event, whether it was clicked, checked, expanded, or collapsed.

To programmatically find out if a node is checked, check the value of its


Checked property.

Tree Nodes and Icons


Each of the nodes we have used so far displayed a simple piece of text. To
enhance the appearance of a node, besides its text, you can display a small
icon to the left of its string. To do this, you must first create an ImageList
control and assign it to the TreeView.ImageList property.

When creating a node, if you plan to display an icon next to it, you can use
the following constructor of the TreeNode class:

C# 3.0 Practical Learning II 840


public TreeNode(String text, int imageIndex, int
selectedImageIndex);

This constructor allows you to specify the text that the node will display, the
index of the picture it will use in the ImageList property, and the picture it
will display when it is selected.

If you are creating a node with its children and you want to specify its
pictures, use the following constructor of the TreeNode class:
public TreeNode(string text,
int imageIndex,
int selectedImageIndex,
TreeNode children[]);

Just as done previously, after defining the TreeNode object, you can add it to
the tree by passing it to the TreeNodeCollection.Add() method. In the
same way, you can create an array of TreeNode objects and pass it to the
TreeNodeCollection.AddRange() method.

Practical Learning: Associating Icons With Nodes

1. To create an icon, on the main menu, click Project -> Add New Item...

2. In the Templates list, click Icon File

3. Set the Name to cpap1 and click Add

4. Right-click the white area and click Delete Image Type

5. Design the 16x16, 16 colors version of the icon as follows:


 

6. On the main menu, click File -> Save cpap1.ico

7. On the main menu, click File -> Close

8. On the main menu, click Project -> Add New Item...

9. In the Templates list, click Icon File

10. Set the Name to cpap2 and click Add

11. Right-click the white area and click Delete Image Type

C# 3.0 Practical Learning II 841


12. Design the 16x16, 16 colors version of the icon as follows:
 

13. On the main menu, click File -> Save cpap2.ico

14. On the main menu, click File -> Close

15. On the main menu, click Project -> Add New Item...

16. In the Templates list, click Icon File

17. Set the Name to year1 and click Add

18. Right-click the white area and click Delete Image Type

19. Design the 16x16, 16 colors version of the icon as follows:


 

20. On the main menu, click File -> Save make2.ico

21. On the main menu, click File -> Close

22. On the main menu, click Project -> Add New Item...

23. In the Templates list, click Icon File

24. Set the Name to year2 and click Add

25. Right-click the white area and click Delete Image Type

26. Design the 16x16, 16 colors version of the icon as follows:


 

C# 3.0 Practical Learning II 842


27. On the main menu, click File -> Save year2.ico

28. On the main menu, click File -> Close

29. On the main menu, click Project -> Add New Item...

30. In the Templates list, click Icon File

31. Set the Name to make1 and click Add

32. Right-click the white area and click Delete Image Type

33. Design the 16x16, 16 colors version of the icon as follows:


 

34. On the main menu, click File -> Save make1.ico

35. On the main menu, click File -> Close

36. On the main menu, click Project -> Add New Item...

37. In the Templates list, click Icon File

38. Set the Name to make2 and click Add

39. Right-click the white area and click Delete Image Type

40. Design the 16x16, 16 colors version of the icon as follows:


 

41. On the main menu, click File -> Save make2.ico

42. On the main menu, click File -> Close

43. On the main menu, click Project -> Add New Item...

44. In the Templates list, click Icon File

45. Set the Name to model1 and click Add

46. Right-click the white area and click Delete Image Type

C# 3.0 Practical Learning II 843


47. Design the 16x16, 16 colors version of the icon as follows:
 

48. On the main menu, click File -> Save model1.ico

49. On the main menu, click File -> Close

50. On the main menu, click Project -> Add New Item...

51. In the Templates list, click Icon File

52. Set the Name to model2 and click Add

53. Right-click the white area and click Delete Image Type

54. Design the 16x16, 16 colors version of the icon as follows:


 

55. On the main menu, click File -> Save model2.ico

56. On the main menu, click File -> Close

57. On the main menu, click Project -> Add New Item...

58. In the Templates list, click Icon File

59. Set the Name to category1 and click Add

60. Right-click the white area and click Delete Image Type

C# 3.0 Practical Learning II 844


61. Design the 16x16, 16 colors version of the icon as follows:
 

62. On the main menu, click File -> Save category1.ico

63. On the main menu, click File -> Close

64. On the main menu, click Project -> Add New Item...

65. In the Templates list, click Icon File

66. Set the Name to category2 and click Add

67. Right-click the white area and click Delete Image Type

68. Design the 16x16, 16 colors version of the icon as follows:


 

69. On the main menu, click File -> Save category2.ico

70. On the main menu, click File -> Close

71. Display the form.


In the Toolbox, click ImageList and click the form

72. In the Properties window, click (Name) and type imgAutoParts

73. Click the ellipsis button of the Images field

74. In Image Collection Editor, click Add

75. Locate the folder that contains the icons you created and display it in the
Look In combo box

76. Select cpap1.ico and click Open

77. In the same way, add the other pictures in the following order:
cpap2.ico, year1.ico, year2.ico, make1.ico, make2.ico, model1.ico,
model2.ico, category1.ico, and category1.ico

C# 3.0 Practical Learning II 845


 

78. Click OK

79. On the form, click the tree view

80. In the Properties window, click ImageList, then click the arrow of its
combo box and select imgAutoParts

81. Access the Central.cs source file and change the code of the Load event
as follows:
 
private void Central_Load(object sender, EventArgs e)
{
TreeNode nodRoot = tvwAutoParts.Nodes.Add("College
Park Auto-Parts",
"College
Park Auto-Parts", 0, 1);

. . . No Change

// Showing the years nodes


for (int years = DateTime.Today.Year + 1; years >
1960; years--)
nodRoot.Nodes.Add(years.ToString(),
years.ToString(), 2, 3);

// Expand the root node


tvwAutoParts.ExpandAll();

// Showing the makes nodes


foreach (TreeNode nodYear in nodRoot.Nodes)
{

C# 3.0 Practical Learning II 846


ArrayList lstMakes = new ArrayList();

foreach (PartDescription part in parts)


{
if (nodYear.Text == part.CarYear.ToString())
{
if (!lstMakes.Contains(part.Make))
lstMakes.Add(part.Make);
}
}

foreach (string strMake in lstMakes)


nodYear.Nodes.Add(strMake, strMake, 4, 5);
}

// Showing the models nodes


foreach (TreeNode nodYear in nodRoot.Nodes)
{
foreach (TreeNode nodMake in nodYear.Nodes)
{
ArrayList lstModels = new ArrayList();

foreach (PartDescription part in parts)


{

if ((nodYear.Text ==
part.CarYear.ToString()) &&
(nodMake.Text == part.Make))
{
if (!lstModels.Contains(part.Model))
lstModels.Add(part.Model);

}
}

foreach (string strModel in lstModels)


nodMake.Nodes.Add(strModel, strModel, 6,
7);
}
}

// Showing the categories nodes


foreach (TreeNode nodYear in nodRoot.Nodes)
{
foreach (TreeNode nodMake in nodYear.Nodes)
{
foreach (TreeNode nodModel in nodMake.Nodes)
{
ArrayList lstCategories = new
ArrayList();

foreach (PartDescription part in parts)


{

if ((nodYear.Text ==
part.CarYear.ToString()) &&

C# 3.0 Practical Learning II 847


(nodMake.Text == part.Make) &&
(nodModel.Text == part.Model))
{
if (!
lstCategories.Contains(part.Category))

lstCategories.Add(part.Category);
}
}

foreach (string strCategory in


lstCategories)
nodModel.Nodes.Add(strCategory,
strCategory, 8, 9);
}
}
}

tvwAutoParts.SelectedNode = nodRoot;
}

82. Execute the application to test it

83. Close the form and return to your programming environment

C# 3.0 Practical Learning II 848


Windows Controls: The Color Dialog
Box
 

Introduction
To provide the selection of colors on Microsoft Windows applications, the
operating system provides a common dialog box appropriate for such tasks.
You can use the Color dialog box for various reasons such as letting the user
set or change a color of an object or specifying the background color of a
control or the color used to paint an object. When it displays, by default, the
dialog box appears as follows:

C# 3.0 Practical Learning II 849


This displays a constant list of colors to the user. If none of the available
colors is appropriate for the task at hand, the user can click the Define
Custom Colors >> button to expand the dialog box:

The expanded Color dialog box allows the user either to select one of the
preset colors or to custom create a color by specifying its red, green, and blue
values.

The user can change the color in four different areas. The top left section
displays a list of 48 predefined colors. If the desired color is not in that
section, the user can click and drag the mouse in the multi-colored palette.
The user can also drag the right bar that displays a range based on the color

C# 3.0 Practical Learning II 850


of the palette; the user can scroll up and down by dragging the arrow. For
more precision, the user can type the Red, Green and Blue values. Each uses
an integral value that ranges from 1 to 255.

Making a Color Dialog Box Available


To provide the Color dialog box to your application, from the Dialogs section
of the Toolbox, you can click the ColorDialog button and click anywhere on
the form. The Color dialog box is implemented through the ColorDialog
class, which is based on the CommonDialog class that is the ancestor to all
Windows common dialog boxes of the .NET Framework. To display the dialog
box to the user, call the CommonDialog.ShowDialog() method. Here is an
example:
private void btnBackColor_Click(object sender, EventArgs e)
{
ColorDialog dlg = new ColorDialog();

dlg.ShowDialog();
}

The Characteristics of the Color Dialog Box

The Color Produced by a Color Dialog Box


The most important and most obvious property of the Color dialog box is the
color the user would have selected after using it. This selected color is
represented by the ColorDialog.Color property. When you are setting up a
ColorDialog control for your application, if you want to specify the default
color, in the Properties windows, you can click the arrow of the Color
property. This would give you the option to select a color from three available
tabs:

C# 3.0 Practical Learning II 851


At run time, you can set the color programmatically by assigning it a valid
known name of a color:
private void btnBackColor_Click(object sender, EventArgs e)
{
ColorDialog dlg = new ColorDialog();
dlg.Color = Color.Red;
dlg.ShowDialog();
}

When the user has finished using the Color dialog box and clicks OK, you can
find out what color was selected by retrieving the value of the
ColorDialog.Color property. Here is an example:

private void btnBackColor_Click(object sender, EventArgs e)


{
ColorDialog dlg = new ColorDialog();
dlg.Color =
Color.FromKnownColor(KnownColor.DarkTurquoise);

if( dlg.ShowDialog() == DialogResult.OK )


panel1.BackColor = dlg.Color;
}

The Full View of a Color Dialog Box


By default, the Color dialog box comes up in its regular (small) size. This
allows the user to select one of the preset colors. If the desired color is not
available, as mentioned already, the user can click the Define Custom Colors
>> button. If you want to control the user's ability to expand the dialog box,
use the Boolean AllowFullOpen property. When this property is set to True,
which is its default value, the dialog box appears in its regular size but with
the Define Custom Colors >> button enabled. If you want the user to be able
to select only one of the preset colors and not have the ability to expand the
dialog box, set the AllowFullOpen property to False. With this value, when
the Color dialog box comes up, it is in its regular size but the Define Custom
Colors >> button is disabled:

C# 3.0 Practical Learning II 852


As mentioned already, by default, the Color dialog box displays in its regular
size. You can control the regular or full size of the dialog using the Boolean
FullOpen property. When its value is False, which is the default, the dialog
appears regularly. If you want it to appear in its full size, set this property to
True.

The Color of a Pixel

Setting the Color of, or Painting, a Pixel


In our introduction to GDI+, we saw that the screen of a computer monitor
uses a series of horizontal and vertical lines, the intersection of two
perpendicular lines is a pixel. Each pixel holds one color. Of course, two
adjacent pixels can hold the same color or each can hold a different color.

A bitmap is a series of colored adjacent pixels. Put another way, for a group
of pixels to be considered a bitmap, these pixels must constitute a group. A
bitmap is made by specifying the color of each pixel. This means that the
pictures we have used so far were simply made of pixels and each pixel held
an appropriate color.

If you decide to create or design a picture using the tool resources in


Microsoft Visual C++ available from the Resource View (or the Solution
Explorer), you would experiment, on a large scale the ability to specify the
color of each individual pixel, using (a limited list of) colors:

C# 3.0 Practical Learning II 853


 

Actually, when you have a bitmap, you can access any pixel of the picture
and then you can either specify its color or get its current color.

To allow you to specify the color of a pixel, the Bitmap class provides a
method named SetPixel and its syntax is:
public void SetPixel(int x, int y, Color color);

The x and y arguments represent the left and top values of the location of the
pixel. The 3rd argument specifies the new color that the pixel will hold. Here
is an example:
private void Form1_Paint(object sender, PaintEventArgs e)
{
Bitmap bgDrawingArea = new Bitmap(Width, Height);
e.Graphics.DrawImage(bgDrawingArea, 0, 0);

for (int i = 0; i < Width; i += 20)


for (int j = 0; j < Height; j += 20)
{
bgDrawingArea.SetPixel(i, j, Color.White);

Graphics painter =
Graphics.FromHwnd(Handle);
painter.DrawImage(bgDrawingArea, 0, 0);
}
}

C# 3.0 Practical Learning II 854


Getting the Color of a Pixel
We previously mentioned that a picture was a series of pixels with each pixel
holding a color. As opposed to specifying the color of a pixel, you can retrieve
its color. To support this, the Bitmap class is equipped with a method
named GetPixel. Its syntax is:
public Color GetPixel(int x, int y);

The x and y arguments represent the left and top values of the location of the
pixel whose color you want to get. This method returns the color of that
pixel. 

Windows Control: The Domain Up-


Down
 

Description
A spin button, also called an up-down control, is usually made to display a
numeric value that can then be increased or decreased when the user clicks

C# 3.0 Practical Learning II 855


one of the buttons of the controls. In a Microsoft Windows typical
application, if you wanted to deal with values other than numbers, there
was some gymnastic code to write. Fortunately, the .NET Framework provides
a special spin button that can hold and display values other numbers.

The .NET Framework's domain up-down control is a text-based object


created from a class named DomainUpDown. Like NumericUpDown, the
DomainUpDown class is derived from the UpDownBase class where it gets its
primary functionality from.

Creating a Domain Up-Down Control


At design time, to get a domain up-down control, from the Toolbox, you can
click the DomainUpDown button and click the form. To programmatically
create a domain up-down control, declare a variable of type DomainUpDown,
initialize it and add it to the Controls property of the container that will hold it.
Here is an example:
using System;
using System.Drawing;
using System.Windows.Forms;

public class Exercise : System.Windows.Forms.Form


{
DomainUpDown spnNames;

public Exercise()
{
InitializeComponent();
}

private void InitializeComponent()


{
spnNames = new DomainUpDown();

Controls.Add(spnNames);
}
}

public class Program


{
static int Main()
{
System.Windows.Forms.Application.Run(new Exercise());
return 0;
}
}

This would produce:

C# 3.0 Practical Learning II 856


  

Characteristics of the Numeric Up-


Down Control
 

The Up-Down Alignment


In traditional Win32 programming, the spin button does not have a means of
displaying its value. This means that you usually have to accompany it with
another control such as a text box. You also have to decide whether to place
the text box to the left or the right side of the spin button control. Although
the .NET Framework's up-down controls don't have this limitation, you still
have to decide whether to position the arrow buttons on the left or the right
side of the text box part. This property is controlled by the UpDownAlign
Boolean property whose default value is Right, which places the arrow
buttons on the right side.

If you want the buttons to be positioned on the left, set this property to Left.
The values of this property are managed through the LeftRightAlignment
enumeration of the UpDownBase parent class. Here is an example of aligning
the buttons to the left:
private void InitializeComponent()
{
nudCounter = new NumericUpDown();
nudCounter.Location = new Point(12, 12);
nudCounter.UpDownAlign = LeftRightAlignment.Left;

Controls.Add(nudCounter);
}

This would produce:

C# 3.0 Practical Learning II 857


Intercepting the Arrow Keys
When a spin button control comes up, to use it, the user can click one of the
up or down-pointing buttons, which causes the value to change. The user can
also press the up or down arrow keys to change the value. The ability to use
the keyboard is controlled by the InterceptArrowKeys Boolean property,
whose default value is True, which means the user is allowed to use the
keyboard to change the value of the control. If for some (strange) reason you
want to prevent the user from changing the value using the keyboard, set this
property to False. If this property is set to True, remember that the user can
use the keyboard only after giving focus to the control, which is usually done
by pressing Tab a few times until the control receives focus. Another way the
user can change the value of the control is to manually edit the value of the
text box part of the control.

When the value of an spin button has been changed, the control fires a
ValueChanged() event. This event simply uses an EventArgs class as
argument. If the user decides to manually edit the value of the control by
typing a number in the text box part of the control, the spin button fires a
TextChanged() event.

The Minimum and the Maximum Values


After adding the up-down control to a container such as a form, you change
its characteristics using the Properties window. Probably the most important
piece of information you would need from a spin button is the value it is
holding at a particular time. As mentioned already, the spin button navigates
from a minimum to a maximum value. The values of the control can be
natural or decimal numbers. They are actually defined as System.Decimal
types. These numbers range from a minimum controlled by the Minimum
property to a maximum value controlled by the Maximum property. By default,
a freshly added numeric up-down control on a form has its Minimum value set
to 0 and its Maximum value set to 100. You can change the values at design
time in the Properties window or programmatically as follows:
private void InitializeComponent()
{
nudCounter = new NumericUpDown();
nudCounter.Location = new Point(12, 12);
nudCounter.Minimum = 42.48M;
nudCounter.Maximum = 3822046.06M;

Controls.Add(nudCounter);
}

If you use large numbers in the thousands, they may become difficult to read:

C# 3.0 Practical Learning II 858


The Value of the Control
When, or while, a spin button is being used, its text box displays a value: this
is the Value property. You can use this property to specify what value the
control would use at startup. It can be an integer or a decimal number but it
must be between the Minimum and the Maximum values. 

The Type of Value


By default, the numeric up-down displays natural numbers. Alternatively, you
can make the spin button display hexadecimal numbers. The type of numbers
displayed is controlled by the Boolean Hexadecimal property whose default
value is False, which means that it is primarily meant to display natural
numbers. If you prefer the control to display hexadecimal numbers, set this
property to True. Here is an example:
private void InitializeComponent()
{
nudCounter = new NumericUpDown();
nudCounter.Location = new Point(12, 12);
nudCounter.Minimum = 42.48M;
nudCounter.Maximum = 3822046.06M;
nudCounter.Hexadecimal = true;

Controls.Add(nudCounter);
}

This would produce:

Displaying Decimal Numbers


By default, the numeric up-down control is made to display only natural
numbers. If you want it to display decimal numbers, use the DecimalPlaces
property to specify the number of decimal places on the right side of the
decimal separator which, in US English, is the period.

The Thousand Separator


If you want to make the control's numeric values easier to read, you can
display a symbol to separate the thousands. This characteristic can be set

C# 3.0 Practical Learning II 859


using the Boolean ThousandsSeparator property whose default value is
False. If you want to display a symbol between thousands, set this property
to True. Here is an example:
private void InitializeComponent()
{
nudCounter = new NumericUpDown();
nudCounter.Location = new Point(12, 12);
nudCounter.Minimum = 42.48M;
nudCounter.Maximum = 3822046.06M;
nudCounter.ThousandsSeparator = true;

Controls.Add(nudCounter);
}

This causes the control to check the value used as the thousands separator in
the Control Panel of the computer that is using the application. The thousands
separator for US English is the comma ",". Here is an example:

The Incrementing Value


When using the spin button, the user clicks one of the arrows of the control
to increase or decrease the value. By default, the value increases or
decreases by 1. If you want the value to augment by more than 1, set the
desired value using the Increment property. The value of this property can
be a natural or a decimal value (it is defined as System.Decimal). To set the
Increment value programmatically, you can use code as follows:

private void InitializeComponent()


{
nudCounter = new NumericUpDown();
nudCounter.Location = new Point(12, 12);
nudCounter.Minimum = 42.48M;
nudCounter.Maximum = 3822046.06M;
nudCounter.Increment = 125.82M;
nudCounter.ThousandsSeparator = true;

Controls.Add(nudCounter);
}

Applications:
Pledge Distribution

C# 3.0 Practical Learning II 860


Windows Control: The Label
 

Introduction to Labels

Description
A label is a control that serves as a guide to the user. It provides static text that the user
cannot change but can read to get information on a form. The programmer can also use
it to display simple information to the user. Most controls on the form are not explicit at
first glance and the user may not know what they are used for. Therefore, you can assign
a label to a control as a help to the user.

Creating a Label

To add a label to a container, click the Label button from the Toolbox and
click the object that would host it.

To programmatically create a label, declare a handle to Label, initialize it


using its default constructor, and add it to the Controls property of the
form. Here is an example:
using System;
using System.Drawing;
using System.Windows.Forms;

public class Exercise : System.Windows.Forms.Form


{
Label lblMessage;

public Exercise()
{
InitializeComponent();
}

private void InitializeComponent()


{
lblMessage = new Label();
Controls.Add(lblMessage);
}
}

public class Program

C# 3.0 Practical Learning II 861


{
static int Main()
{

System.Windows.Forms.Application.Run(new Exercise());

return 0;
}
}

Practical Learning: Introducing Labels

1. Start Microsoft Visual C# and create a Windows Application named


ElementaryAddition1

2. From the Common Control section of the Toolbox, click Label and click
the form

3. From the Common Control section of the Toolbox, click the Label again
and click the form

4. From the Common Control section of the Toolbox, click the Label again
and click the form

Characteristics of a Label

The Caption
The most important characteristic of a label control is the text it displays. That
text is also referred to as its caption and this is what the user would read.
The text of a label is its Text property and is its default. To set a label’s
caption, after adding the control to a container, click Text in the Properties
window and type the desired value. As we mentioned when studying controls
characteristics, at design time, the text you type in the Text field is
considered “as is”. If you want to create a more elaborate and formatted
string, you would have to do it programmatically. Here is an example:
public class Exercise : System.Windows.Forms.Form
{
Label lblMessage;

public Exercise()
{
InitializeComponent();
}

private void InitializeComponent()


{

C# 3.0 Practical Learning II 862


lblMessage = new Label();
lblMessage.Text = DateTime.Now.ToString();
Controls.Add(lblMessage);
}
}

Here is an example of what this would produce:

When it comes to its caption, one of the most valuable characteristics of the
text of a label is the variance of the font. When designing a caption. you can
change the default font to make it more attractive.

Practical Learning: Captioning the Labels

1. On the form, click the first label

2. In the Properties window, click Text and type 00

3. Click (Name) and type lblOperand1

4. Click TextAlign and the arrow of its combo box to select Center

5. Click the + button of the Font field and change the characteristics as
follows:
Name: Tahoma
Size:   48
Bold:   True

6. On the form, click the second label and, in the Properties window,
change its characteristics as follows:
Text: +
TextAlign: Center
(Name): lblOPeration
Font -> Name: Arial
Font -> Size:   50
Font -> Bold:   True

7. On the form, click the third label and, in the Properties window, change
its characteristics as follows:
Text: 00
TextAlign: Center
(Name): lblOperand2
Font -> Name: Arial
Font -> Size:   50
Font -> Bold:   True

C# 3.0 Practical Learning II 863


8. Save all

Automatically Sizing a Label


After adding a label to a form, by default, it receives a fixed size. If you type
its caption and press Enter, the text you provided would be confined to the
allocated dimensions of the control. If the text is too long, part of it may
disappear. You can then resize the label to provide more area. Another
solution is to automatically resize the label to accommodate the length of the
string you typed. This is aspects is controlled by the Boolean AutoSize
property. Its default value is False. If you set this property to True, at design
time, a rectangular border appears around it. If you type a string in the Text
field and press Enter, the control would be resized to show the whole string
but using only the necessary space.

If you programmatically create a label, it assumes a default size. If you assign


it a string that is too long for that default size, part of the string may appear
on a subsequent line. If you want the whole string to appear on the same
line, you can set the AutoSize to true. Here is an example:
public class Exercise : System.Windows.Forms.Form
{
Label lblMessage;

public Exercise()
{
InitializeComponent();
}

private void InitializeComponent()


{
lblMessage = new Label();
lblMessage.Text = DateTime.Now.ToString();
lblMessage.AutoSize = true;
Controls.Add(lblMessage);
}
}

Here is an example of what this would produce:

Practical Learning: Using AutoSize

1. Click an unoccupied area of the form and press Ctrl + A to select all
three labels

2. In the Properties window, double-click AutoSize to set the value to False

C# 3.0 Practical Learning II 864


3. Save all

Content Alignment
After typing the caption of a label whose AutoSize property is set to False,
you can resize its allocated space to your liking. This is because a string
occupies a rectangular area. Here is an example:

By default, the caption of a label is positioned starting on the middle-left side


of its allocated rectangle. Alternatively, you can position it to one of the nine
available positions. As we saw is Lesson 5, the position of the caption of a
label is controlled by the TextAlign property which is based on the
ContentAlignment enumerator:

It can have the following values:

TopLeft TopCenter TopRight

MiddleLeft MiddleCenter MiddleRight

C# 3.0 Practical Learning II 865


BottomLeft BottomCenter BottomRight

Pictures on a Label
Other fancy characteristics you can apply to a label include its font and color.
For example, a label is primarily meant to display a string. To make it fancier,
you can display a (small) picture next to it. To do this, at design time, use the
Image field of the Properties window to select a picture. You can also specify
the picture at run time by assigning an Image value to the Label.Image
property. After adding a picture that would accompany the label, you can
specify what position the picture would hold with regards to the label. To do
this, select the desired position of the ImageAlign field in the Properties
window.

Instead of using a picture from the Image property, you can create a list of
images using an ImageList control and assign it to the label. In fact, the
advantage of an ImageList is that, unlike the Image property, it allows you
to use more than one picture.

After assigning an ImageList to the label control using the Properties


window or code, you can use the ImageIndex to specify what picture to
display next to the label.

A Label's Mnemonic
A label provides another property called UseMnemonic. This property is
valuable only when the label accompanies another control.

Practical Learning: Using a Text Box

1. Complete the design of the form as follows:


 

C# 3.0 Practical Learning II 866


Additional
Control Text Name TextAlign Font
Properties

Name:
Tahoma
Label 00 lblOperand1 Center Size:   48 ForeColor: Blue
Bold:  
True

Name:
Arial
Label +   Center Size:   50 ForeColor: Maroon
Bold:  
True

Name:
Tahoma
Label 00 lblOperand2 Center Size:   48 ForeColor: Blue
Bold:  
True

Name:
Arial
Label =   Center Size:   50 ForeColor: Green
Bold:  
True

Label 00 lblResult Center Name:  


Tahoma
Size:   48
Bold:  

C# 3.0 Practical Learning II 867


True

Name:
BorderStyle:
Tahoma,
New Fixed3D
Label lblNewOperation Center Size: 28
Operation ForeColor: White
Bold:
BackColor:Maroon 
True

Name:
Tahoma,
BorderStyle:
Label Quit lblQuit Center Size: 28
FixedSingle
Bold:
True

2. To be able to use the Visual Basic library, in the Solution Explorer, right-
click References -> Add References...

3. In the .NET property page, click Microsoft.VisualBasic


 

4. Click OK and OK

5. Double-click New Operation and implement its event as follows:


 
private void lblNewOperation_Click(object sender, EventArgs e)
{

C# 3.0 Practical Learning II 868


int operand1;
int operand2;
int answer = 0;

Random rnd = new Random();

operand1 = rnd.Next(99);
operand2 = rnd.Next(99);
int result = operand1 + operand2;

lblOperand1.Text = operand1.ToString();
lblOperand2.Text = operand2.ToString();
lblResult.Text = "0";
string strPrompt = lblOperand1.Text + " + " +
lblOperand2.Text + " =";

try
{
answer =

int.Parse(Microsoft.VisualBasic.Interaction.InputBox(
strPrompt,
"Elementary Addition",
"000",
100,
100));

lblResult.Text = answer.ToString();

if (answer == result)
MessageBox.Show("WOW - Good Answer");
else
MessageBox.Show("PSSST - Wrong Answer");
}
catch (FormatException)
{
}
}

6. Return to the form and double-click Quit

7. Implement its event as follows:


 
private void lblQuit_Click(object sender, EventArgs e)
{
Close();
}

8. Execute the application and test it


 

C# 3.0 Practical Learning II 869


 

C# 3.0 Practical Learning II 870


 

9. Click the Close button to close the form and return to your programming
environment

C# 3.0 Practical Learning II 871


Application Menus: The Main Menu
 

Introduction
When it comes to a restaurant, a menu is a list of food items that the
business offers to its customers. For a computer application, a menu is a list
of actions that can be performed on that program. To be aware of these
actions, the list must be presented to the user upon request. On a typical
DOS application, a menu is presented with numerical or character options
that the user can select from. An example would be:

Here are the various options:


1. Register a new student
2. Review a student's information
3. Enter student's grades
4. Close the application

The user would then enter the number (or character) that corresponds to the
desired option and continue using the program. For a graphical application, a
menu is presented as a list of words and, using a mouse or a keyboard, the
user can select the desired item from the menu.

To enhance the functionality of a graphical application, also to take advantage


of the mouse and the keyboard, there are various types of menus. A menu is
considered a main menu when it carries most of the actions the user can
perform on a particular application. Such a menu is positioned in the top
section of the form in which it is used.

A main menu is divided in categories of items and each category is


represented by a word. In WordPad, the categories of menus are File, Edit,
View, Insert, Format, and Help:

To use a menu, the user first clicks one of the words that displays on top.
When clicked, the menu expands and displays a list of items that belong to
that category. Here is an example:

C# 3.0 Practical Learning II 872


There is no strict rule on how a menu is organized. There are only
suggestions. For example, actions that are related to file processing, such as
creating a new file, opening an existing file, saving a file, printing the open
file, or closing the file usually stay under a category called File. In the same
way, actions related to viewing documents can be listed under a View menu
category.

Main Menu Creation


To support actions that are used to graphically enhance the functionality of
an application, the .NET Framework provides the ToolStrip class. To
support menus for an application, the .NET Framework provides the
MenuStrip class (in Microsoft Visual Studio 2002 and 2003, the main menu
was implemented through the MainMenu class, which is still available but
lacks some features).

To graphically create a main menu, in the Menus & Toolbars section of the
Toolbox, you can click the MenuStrip button and click the form that will
use the menu. After clicking the form, an empty menu is initiated:

Like every control, the main menu must have a name. After adding the menu
strip to a form, you can accept the suggested name or, in the Properties
window, click (Name) and type the desired name. You can then use the menu
placeholder to add the necessary menu item(s)..

To programmatically create a main menu, declare a handle to MenuStrip


class and initialize it with its default constructor. Because the main menu is

C# 3.0 Practical Learning II 873


primarily a control, you must add it to the list of controls of the form. Here is
an example:
using System;
using System.Drawing;
using System.Windows.Forms;

public class Exercise : System.Windows.Forms.Form


{
MenuStrip mnuMain;

public Exercise()
{
InitializeComponent();
}

void InitializeComponent()
{
mnuMain = new MenuStrip();
Controls.Add(mnuMain);
}
}

public class Program


{
static int Main()
{
System.Windows.Forms.Application.Run(new Exercise());
return 0;
}
}

Menu Categories
In our introduction, we saw that a main menu was made of categories
represented in the top section. After adding a MenuStrip, you can start
creating the desired menu categories. To graphically create a menu category:

 In the menu strip, you can click the Type Here line and type the desired
string

 In the menu strip, you can click Type Here. Then, in the Properties
window, click the Text field and type the desired string

To create the next menu category, you can click Type Here on the right side of
the previous menu category. In the same way, you can continue creating the
desired menu categories.

Here is an example:

C# 3.0 Practical Learning II 874


Besides clicking Type Here and typing a string, an alternative is to get
assisted by a dialog box. To open it:

 Under the form, you can click the menu strip object and, in the
Properties window, you can click the ellipsis button of the Items field

 Under the form, you can right-click the menu strip and click Edit Items...

A dialog box, titled Items Collection Editor, would come up:

To create a menu category, in the Select Item And Add To List Below combo
box, select MenuItem and click the Add button. In the right list, configure the
menu item. At a minimum, you should specify its caption in the Text field.
Like every control, each menu item has a name. To make sure you can easily
recognize it in your code, when creating a menu item, you should give it a
name unless you are contempt with the suggested one. After creating the
menu categories, you can click OK and keep the dialog box opened for more
options.

To support menuitems, the .NET Framework provides the


ToolStripMenuItem class. Using it, to create a menu category, declare a

C# 3.0 Practical Learning II 875


handle to this class and initialize it using one of its constructors. The default
constructor is used to create a menu item without specifying any of its
options. Here is an example:
public class Exercise : System.Windows.Forms.Form
{
MenuStrip mnuMain;
ToolStripMenuItem mnuFile;

public Exercise()
{
InitializeComponent();
}

void InitializeComponent()
{
mnuMain = new MenuStrip();
mnuFile = new ToolStripMenuItem();

Controls.Add(mnuMain);
}
}

To specify the caption that will be displayed on a menu category, you can use
the following constructor of the ToolStripMenuItem class:
public ToolStripMenuItem(string text);

Here is an example:
public class Exercise : System.Windows.Forms.Form
{
MenuStrip mnuMain;
ToolStripMenuItem mnuFile;

public Exercise()
{
InitializeComponent();
}

void InitializeComponent()
{
mnuMain = new MenuStrip();
mnuFile = new ToolStripMenuItem("File");

Controls.Add(mnuMain);
}
}

If you had instantiated the class using its default constructor, to specify its
caption, the ToolStripMenuItem class is equipped with the Text property.
Therefore, assign a string to this property. Here is an example:
public class Exercise : System.Windows.Forms.Form
{
MenuStrip mnuMain;

C# 3.0 Practical Learning II 876


ToolStripMenuItem mnuFile;
ToolStripMenuItem mnuEdit;

public Exercise()
{
InitializeComponent();
}

void InitializeComponent()
{
mnuMain = new MenuStrip();
mnuFile = new ToolStripMenuItem("File");
mnuEdit = new ToolStripMenuItem();
mnuEdit.Text = "Edit";

Controls.Add(mnuMain);
}
}

In the same way, you can create as many menu categories as you judge
necessary for your application.

Introduction to Menu Items


In our introduction, we saw that if you click a menu category, a list comes up.
Here is an example:

The objects under a menu category are referred to as menu items. To


graphically create a menu item, first access the menu strip, which you can do
by clicking it under the form. On the form, click a menu category. Once you
do, a placeholder would be displayed under it:

To create a menu item:

 Under a category, click Type Here and type the desired caption. 

C# 3.0 Practical Learning II 877


 Click the menu category. Then, in the Properties window, click Text and
type the desired string.

In the same way, to create the next menu item, under the same category, click
the next Type Here and type the desired caption or change the Text value in
the Properties window.

An alternative is to use a dialog box. To access it, in the menu designer:

 Right-click the menu category and click Edit Drop Down Items...

 Click the menu category. Then, in the Properties window, click the
ellipsis button of the DropDownItems field

The Items Collection Editor dialog box would come up:

To create a menu item, in the Select Item And Add To List Below combo box,
select MenuItem and click Add. On the right side, configure the menu item as
you see fit. At a minimum, you should specify its caption in the Text field.

Both the menu category and the menu item are created using the
ToolStripMenuItem class. Here are examples:

public class Exercise : System.Windows.Forms.Form


{
MenuStrip mnuMain;
ToolStripMenuItem mnuFile;
ToolStripMenuItem mnuNew;
ToolStripMenuItem mnuExit;
ToolStripMenuItem mnuEdit;

C# 3.0 Practical Learning II 878


ToolStripMenuItem mnuCopy;

public Exercise()
{
InitializeComponent();
}

void InitializeComponent()
{
mnuMain = new MenuStrip();
mnuFile = new ToolStripMenuItem("File");
mnuNew = new ToolStripMenuItem("New");
mnuExit = new ToolStripMenuItem("Exit");
mnuEdit = new ToolStripMenuItem("Edit");
mnuCopy = new ToolStripMenuItem("Copy");

Controls.Add(mnuMain);
}
}

Associating Menu Items to Menu Categories


If you visually create your main menu, the form designer takes care of most
details behind the scenes. For example, each menu item is automatically
added to its parent menu category. If you programmatically create your main
menu, you must associate each menu item to its parent menu category.

To support menu categories, ToolStripMenuItem, the class used to create


menu categories, is derived from a class named ToolStripDropDownItem.
The ToolStripDropDownItem class is abstract, which means you cannot
instantiate it. Instead, it provides functionality to other classes derived from
it. The ToolStripDropDownItem class is based on the ToolStripItem class.

To support menu items, the ToolStripDropDownItem class is equipped with


a property named DropDownItems. This property is of type
ToolStripItemCollection, which a collection-based class. The
ToolStripItemCollection class implements the IList and the
ICollection interfaces.

To specify that a menu item will be part of a menu category, call the Add()
method of the ToolStripItemCollection class. This method is overloaded
with various versions. One of the versions uses the following syntax:
public int Add(ToolStripItem value);

This version allows you to pass a ToolStripItem-type of item class, such as


a ToolStripMenuItem object. Here is an example:
public class Exercise : System.Windows.Forms.Form
{
MenuStrip mnuMain;
ToolStripMenuItem mnuEdit;

C# 3.0 Practical Learning II 879


ToolStripMenuItem mnuCopy;

public Exercise()
{
InitializeComponent();
}

void InitializeComponent()
{
mnuMain = new MenuStrip();
mnuEdit = new ToolStripMenuItem("Edit");
mnuCopy = new ToolStripMenuItem("Copy");
mnuEdit.DropDownItems.Add(mnuCopy);

Controls.Add(mnuMain);
}
}

The ToolStripItemCollection class also allows you to create a menu item


without going through a ToolStripItem-type of object. To support this, its
provides the following version of its Add() method:
public ToolStripItem Add(string text);

This method takes as argument the text that the menu item would display
and it returns the ToolStripItem item that was created. Here is an example:
public class Exercise : System.Windows.Forms.Form
{
MenuStrip mnuMain;
ToolStripMenuItem mnuEdit;
ToolStripMenuItem mnuCopy;
ToolStripMenuItem mnuPaste;

public Exercise()
{
InitializeComponent();
}

void InitializeComponent()
{
mnuMain = new MenuStrip();
mnuEdit = new ToolStripMenuItem("Edit");
mnuCopy = new ToolStripMenuItem("Copy");
mnuEdit.DropDownItems.Add(mnuCopy);
mnuPaste =
(ToolStripMenuItem)mnuEdit.DropDownItems.Add("Paste");

Controls.Add(mnuMain);
}
}

Instead of adding one menu item at a time, you can create an array of menu
items and then add it to a category in one row. To support this, the
ToolStripItemCollection class implements the AddRange() method. This

C# 3.0 Practical Learning II 880


method is overloaded with two versions. One of the versions uses the
following syntax:
public void AddRange(ToolStripItem[] toolStripItems);

When calling this method, you must pass it an array of ToolStripItem-type


of objects. Here are two examples:
public class Exercise : System.Windows.Forms.Form
{
MenuStrip mnuMain;
ToolStripMenuItem mnuFile;
ToolStripMenuItem mnuNew;
ToolStripMenuItem mnuOpen;
ToolStripMenuItem mnuExit;
ToolStripMenuItem mnuEdit;
ToolStripMenuItem mnuCopy;
ToolStripMenuItem mnuPaste;
ToolStripMenuItem mnuHelp;

public Exercise()
{
InitializeComponent();
}

void InitializeComponent()
{
mnuMain = new MenuStrip();

mnuFile = new ToolStripMenuItem("File");


mnuNew = new ToolStripMenuItem("New");
mnuOpen = new ToolStripMenuItem("Open");
mnuExit = new ToolStripMenuItem("Exit");
ToolStripMenuItem[] mnuFileItems = { mnuNew, mnuOpen,
mnuExit };
mnuFile.DropDownItems.AddRange(mnuFileItems);

mnuEdit = new ToolStripMenuItem("Edit");


mnuCopy = new ToolStripMenuItem("Copy");
mnuEdit.DropDownItems.Add(mnuCopy);
mnuPaste =
(ToolStripMenuItem)mnuEdit.DropDownItems.Add("Paste");

mnuHelp = new ToolStripMenuItem("Help");


ToolStripMenuItem[] mnuHelpItems =
{
new ToolStripMenuItem("Search"),
new ToolStripMenuItem("Contents"),
new ToolStripMenuItem("Index"),
new ToolStripMenuItem("Support Web Site"),
new ToolStripMenuItem("About this application")
};
mnuHelp.DropDownItems.AddRange(mnuHelpItems);

Controls.Add(mnuMain);
}

C# 3.0 Practical Learning II 881


}

Associating Menu Categories to the Main Menu 


If you visually create your main menu, each menu category is automatically
assigned to the menu strip. If you programmatically create your main menu,
you must take care of this in order to show the whole menu.

After creating the menu categories, you can add them to the main menu. To
support this, the ToolStrip class is equipped with a property named Items
and it makes this property available to the MenuStrip class. The Items
property is of type ToolStripItemCollection. This class implements the
IList, the ICollection, and the IEnumerable interfaces. Therefore, to add
a menu category to a MenuStrip object, you can call the Add() method of
the ToolStripItemCollection class. This method is overloaded with
various versions and one of them uses the following version:
public int Add(ToolStripItem value);

You can call this version and pass it a ToolStripItem-type of object, such as
a ToolStripMenuItem value. Here is an example:
public class Exercise : System.Windows.Forms.Form
{
MenuStrip mnuMain;
ToolStripMenuItem mnuFile;
ToolStripMenuItem mnuNew;
ToolStripMenuItem mnuOpen;
ToolStripMenuItem mnuExit;
ToolStripMenuItem mnuEdit;
ToolStripMenuItem mnuCopy;
ToolStripMenuItem mnuPaste;
ToolStripMenuItem mnuHelp;

public Exercise()
{
InitializeComponent();
}

void InitializeComponent()
{
mnuMain = new MenuStrip();

mnuFile = new ToolStripMenuItem("File");


mnuNew = new ToolStripMenuItem("New");
mnuOpen = new ToolStripMenuItem("Open");
mnuExit = new ToolStripMenuItem("Exit");
ToolStripMenuItem[] mnuFileItems = { mnuNew, mnuOpen,
mnuExit };
mnuFile.DropDownItems.AddRange(mnuFileItems);

mnuEdit = new ToolStripMenuItem("Edit");


mnuCopy = new ToolStripMenuItem("Copy");

C# 3.0 Practical Learning II 882


mnuEdit.DropDownItems.Add(mnuCopy);
mnuPaste =
(ToolStripMenuItem)mnuEdit.DropDownItems.Add("Paste");

mnuHelp = new ToolStripMenuItem("Help");


ToolStripMenuItem[] mnuHelpItems =
{
new ToolStripMenuItem("Search"),
new ToolStripMenuItem("Contents"),
new ToolStripMenuItem("Index"),
new ToolStripMenuItem("Support Web Site"),
new ToolStripMenuItem("About this application")
};
mnuHelp.DropDownItems.AddRange(mnuHelpItems);

mnuMain.Items.Add(mnuFile);
Controls.Add(mnuMain);
}
}

In the same way, you can add the other items. Alternatively, you can create
an array of menu categories and add them in a row. To support this, the
ToolStripItemCollection is equipped with the AddRange() method that is
overloaded with two versions. One of the versions uses the following syntax:
public void AddRange(array<ToolStripItem>toolStripItems);

When calling this method, pass it an array of ToolStripItem types of values.


Here is an example:
public class Exercise : System.Windows.Forms.Form
{
MenuStrip mnuMain;
ToolStripMenuItem mnuFile;
ToolStripMenuItem mnuNew;
ToolStripMenuItem mnuOpen;
ToolStripMenuItem mnuExit;
ToolStripMenuItem mnuEdit;
ToolStripMenuItem mnuCopy;
ToolStripMenuItem mnuPaste;

ToolStripMenuItem mnuView;

ToolStripMenuItem mnuHelp;

public Exercise()
{
InitializeComponent();
}

void InitializeComponent()
{
mnuMain = new MenuStrip();

mnuFile = new ToolStripMenuItem("File");

C# 3.0 Practical Learning II 883


mnuNew = new ToolStripMenuItem("New");
mnuOpen = new ToolStripMenuItem("Open");
mnuExit = new ToolStripMenuItem("Exit");
ToolStripMenuItem[] mnuFileItems = { mnuNew, mnuOpen,
mnuExit };
mnuFile.DropDownItems.AddRange(mnuFileItems);

mnuEdit = new ToolStripMenuItem("Edit");


mnuCopy = new ToolStripMenuItem("Copy");
mnuEdit.DropDownItems.Add(mnuCopy);
mnuPaste =
(ToolStripMenuItem)mnuEdit.DropDownItems.Add("Paste");

mnuView = new ToolStripMenuItem("View");


ToolStripMenuItem[] mnuViewItems =
{
new ToolStripMenuItem("Standard Toolbar"),
new ToolStripMenuItem("Formatting Toolbar"),
new ToolStripMenuItem("Status Bar")
};
mnuView.DropDownItems.AddRange(mnuViewItems);

mnuHelp = new ToolStripMenuItem("Help");


ToolStripMenuItem[] mnuHelpItems =
{
new ToolStripMenuItem("Search"),
new ToolStripMenuItem("Contents"),
new ToolStripMenuItem("Index"),
new ToolStripMenuItem("Support Web Site"),
new ToolStripMenuItem("About this application")
};
mnuHelp.DropDownItems.AddRange(mnuHelpItems);

ToolStripMenuItem[] mnuAccessories = { mnuView,


mnuHelp };

mnuMain.Items.Add(mnuFile);
mnuMain.Items.AddRange(mnuAccessories);

Controls.Add(mnuMain);
}
}

This would produce:

C# 3.0 Practical Learning II 884


Practical Learning: Creating a Menu

1. Start Microsoft Visual C#

2. Create a new Windows Application named AltairRealtors3

3. From the Menus & Toolbars section of the Toolbox, click the MenuStrip
button and click the form

4. While the menu strip is still selected, in the Properties window, click
(Name), type mnuMain and press Enter

5. On the form, click Type Here, type File and press Enter

6. On the form, click File.


In the Properties window, click (Name) and type mnuFile

7. On the form, click File and under it, click the Type Here box

8. Type New Property and press Enter

9. On the form, click File and click New Property.


In the Properties window, click (Name) and type mnuFileNewProperty

10. On the form, click File and, under New Property, click the Type Here box

11. Type Exit and press Enter

12. On the form, click File and click Exit.


In the Properties window, click (Name) and type mnuFileExit

13. Complete the design of the form as follows:


 

C# 3.0 Practical Learning II 885


Control Text Name Other Properties

MenuStrip      

Font: Times New


Roman, 21.75pt,
Altair Realtors -
Label   style=Bold
Properties Listing
ForeColor:
MediumBlue

ListView   lvwProperties  

Columns (Name) Text TextAlign Width

colPropertyNumber Prop #   50

colPropertyType Property Type   78

colAddress Address   130

colCity City   80

C# 3.0 Practical Learning II 886


colState State   40

colZIPCode ZIP Code Center 58

colBedrooms Beds Right 40

colBathrooms Baths Right 40

colMarketValue Market Value Right 75

14. On the main menu, click Project -> Add Windows Form...

15. Set the Name to RealEstateProperty and click Add

16. Design the form as follows:


 

Control

Text Name Other Properties

Label Property #:    

TextBox   txtPropertyNumber Modifiers: Public

Property
Label    
Type:

C# 3.0 Practical Learning II 887


Modifiers:
Public
Items:
ComboBox   cbxPropertyTypes Unknown
Single Family
Townhouse
Condominium

Label Address:    

TextBox   txtAddress Modifiers: Public

Label City:    

TextBox   txtCity Modifiers: Public

Label State:    

Modifiers: Public
Items:
DC
ComboBox   cbxStates MD
PA
VA
WV

Label ZIP Code:    

TextBox   txtZIPCode Modifiers: Public

Label Bedrooms:    

TextBox 0 txtBedrooms Modifiers: Public

C# 3.0 Practical Learning II 888


Label Bathrooms:    

TextBox 1.0 txtBathrooms Modifiers: Public

Label Market Value:    

TextBox 0.00 txtMarketValue Modifiers: Public

Button OK btnOK DialogResult: OK

DialogResult:
Button Cancel btnCancel
Cancel

Form

FormBorderStyle: FixedDialog

Text: Altair Realtors - Available Property

StartPosition: CenterScreen

AcceptButton: btnOK

CancelButton: btnCancel

MaximizeBox: False

MinimizeBox: False

ShowInTaskBar: False

17. Display the first form

Coding a Menu Item


If you create a menu as we have just done, to write code for one of the menu
items, you can double-click the menu item. This would open the Click event of

C# 3.0 Practical Learning II 889


the menu item in the Code Editor and you can start writing the desired code
for that item.

Practical Learning: Writing Code For a Main Menu

1. On the form, click File and double-click New Property

2. Implement the event as follows:


 
private void mnuFileNewProperty_Click(object sender, EventArgs
e)
{
RealEstateProperty dlgProperty = new RealEstateProperty();

Random rndNumber = new Random(DateTime.Now.Millisecond);


int number1 = rndNumber.Next(100, 999);
int number2 = rndNumber.Next(100, 999);
string propNumber = number1 + "-" + number2;

dlgProperty.txtPropertyNumber.Text = propNumber;
dlgProperty.Text = "Altair Realtors - New Property";

if (dlgProperty.ShowDialog() == DialogResult.OK)
{
string strPropertyType =
dlgProperty.cbxPropertyTypes.Text;
string strAddress = dlgProperty.txtAddress.Text;
string strCity = dlgProperty.txtCity.Text;
string strState = dlgProperty.cbxStates.Text;
string strZIPCde = dlgProperty.txtZIPCode.Text;
string strBedrooms = dlgProperty.txtBedrooms.Text;
string strBathrooms = dlgProperty.txtBathrooms.Text;
string strMarketValue = dlgProperty.txtMarketValue.Text;

ListViewItem lviProperty =
new
ListViewItem(dlgProperty.txtPropertyNumber.Text);

lviProperty.SubItems.Add(strPropertyType);
lviProperty.SubItems.Add(strAddress);
lviProperty.SubItems.Add(strCity);
lviProperty.SubItems.Add(strState);
lviProperty.SubItems.Add(strZIPCde);
lviProperty.SubItems.Add(strBedrooms);
lviProperty.SubItems.Add(strBathrooms);
lviProperty.SubItems.Add(strMarketValue);
lvwProperties.Items.Add(lviProperty);
}
}

3. Return to the (first) form

4. On the form, click File and double-click Exit

C# 3.0 Practical Learning II 890


5. Implement the event as follows:
 
private void mnuFileExit_Click(object
sender, EventArgs e)
{
Close();
}

6. Test the form


 

7. To close it, click File -> Exit

Windows Control: The Panel Control


 

Introduction
The panel is a rectangular object that can provide various valuable services
for application design. A panel allows you to design good-looking forms by
adjusting colors and other properties. A panel can also be used as control
delimiter for objects that behave as a group. An example would be a set of
radio buttons.

As a member of the family of control containers, a panel can be used to hold


or carry controls placed on it. When a panel moves, it does so with the
controls placed on it. When a panel is visible, the controls placed on it can be
visible too, unless they have their own visibility removed. When a panel is

C# 3.0 Practical Learning II 891


hidden, its child controls are hidden too, regardless of their own visibility
status. This property also applies to the panel's availability.

Panels are not transparent. Therefore, their color can be changed to control
their background display. A panel is a complete control with properties,
methods, and events.

Creating a Panel

To add a panel to a container, you can click the Panel button from the
Toolbox and click the desired location on the container. Unlike the form,
during design, a panel must primarily be positioned on another container
which would be a form or another panel.

To programmatically create a panel, declare a handle to Panel, allocate


memory for it using the new operator, and add it to its parent. Here is an
example:
using System;
using System.Drawing;
using System.Windows.Forms;

public class Exercise : System.Windows.Forms.Form


{
Panel pnlContainer;

public Exercise()
{
InitializeComponent();
}

private void InitializeComponent()


{

Text = "Domain Configuration";

Width = 320;
Height = 210;
Location = System.Drawing.Point(140, 100);
StartPosition = FormStartPosition.CenterScreen;

pnlContainer = new Panel();


pnlContainer.Location = Point(20, 20);
pnlContainer.Size = System.Drawing.Size(100, 60);
Controls.Add(pnlContainer);
}
}

public class Program


{
static int Main()
{

C# 3.0 Practical Learning II 892


System.Windows.Forms.Application.Run(new Exercise());

return 0;
}
}

Characteristics of a Panel
By default, a panel object is drawn without borders. If you want to add
borders to it, use the BorderStyle property. It provides three values that you
can set in the Properties window: None, FixedSingle, and Fixed3D and their
effects are as follows:

  None FixedSingle Fixed3D

Design

Run

To programmatically specify the border style, assign the desired value to the
Panel.BorderStyle property. Here is an example:

private void InitializeComponent()


{
Text = "Domain Configuration";
Width = 320;
Height = 210;
Location = System.Drawing.Point(140, 100);
StartPosition = FormStartPosition.CenterScreen;

pnlContainer = new Panel();


pnlContainer.Location = Point(20, 20);
pnlContainer.Size = System.Drawing.Size(100, 60);
pnlContainer.BorderStyle = BorderStyle.Fixed3D;

Controls.Add(pnlContainer);
}

C# 3.0 Practical Learning II 893


A panel can be used as a button, in which case the user would click it to
initiate an action.

A property that is highly used on panels (and forms) is the Color. If you
change the BackColor property, the new color would cover the face of the
panel.

Windows Control: The Radio Buttons


 

Description
A radio button, sometimes called an option button, is a circular control that
comes in a group with other radio buttons. Each radio button is made of a
small empty circle O. From the group, when the user clicks one of them, the
radio button that was clicked becomes filled with a big dot . When one of the
radio buttons in the group is selected and displays its dot, the others display
empty circles. To guide the user as to what the radio buttons mean, each is
accompanied by a label.

Here is an example of a form with three radio buttons: Small, Medium, and
Large

Creating Radio Buttons

C# 3.0 Practical Learning II 894


To create a radio button, on the Toolbox, you can click the RadioButton
control . To programmatically create a radio button, declare a variable of
type RadioButton, use the new operator to allocation memory for it and add
it to the Controls collection of its parent. Because radio buttons always come
as a group, you should include them in another control that visibly shows that
the radio buttons belong together. The most common control used for this
purpose is the group box created using the GroupBox control.

Characteristics of Radio Buttons

The Location of a Radio Button


Unlike most of other controls that can be positioned anywhere, a radio button
should not be placed directly on a form. Instead, a radio button should be
positioned in a container that belongs to a form. The typical container is the
group box. When a radio button is added to a group box, the location of the
radio button is relative to its parent. This location is easy to specify if you are
visually designing the application. If you are programmatically creating it,
make sure you specify the location based on the control that will hold the
radio button. Here are examples:
using System;
using System.Drawing;
using System.Windows.Forms;

public class Exercise : System.Windows.Forms.Form


{
RadioButton radSmall;
RadioButton radMedium;
RadioButton radLarge;
GroupBox grpPizzaSize;

public Exercise()
{
InitializeComponent();
}

private void InitializeComponent()


{
grpPizzaSize = new GroupBox();
grpPizzaSize.Size = new Size(160, 120);
grpPizzaSize.Location = new Point(20, 10);

radSmall = new RadioButton();


radSmall.Location = new Point(20, 20);

radMedium = new RadioButton();


radMedium.Location = new Point(20, 50);

C# 3.0 Practical Learning II 895


radLarge = new RadioButton();
radLarge.Location = new Point(20, 80);

grpPizzaSize.Controls.Add(radSmall);
grpPizzaSize.Controls.Add(radMedium);
grpPizzaSize.Controls.Add(radLarge);

Controls.Add(grpPizzaSize);
}
}
}

public class Program


{
static int Main()
{
System.Windows.Forms.Application.Run(new Exercise());
return 0;
}
}

This would produce:

The Caption of a Radio Button


To indicate what a radio button represents, it is accompanied by text, also
referred to as its caption. To specify the caption of a radio button at a design
time, type a string in the Text field of its Properties window. To
programmatically specify the caption of a radio button, assign a string to its
Text property. Here are examples:

private void InitializeComponent()


{
grpPizzaSize = new GroupBox();
grpPizzaSize.Text = "Pizza Size";
grpPizzaSize.Size = new Size(160, 120);
grpPizzaSize.Location = new Point(20, 10);

radSmall = new RadioButton();


radSmall.Text = "Small";
radSmall.Location = new Point(20, 20);

C# 3.0 Practical Learning II 896


radMedium = new RadioButton();
radMedium.Text = "Medium";
radMedium.Location = new Point(20, 50);

radLarge = new RadioButton();


radLarge.Text = "Large";
radLarge.Location = new Point(20, 80);

grpPizzaSize.Controls.Add(radSmall);
grpPizzaSize.Controls.Add(radMedium);
grpPizzaSize.Controls.Add(radLarge);

Controls.Add(grpPizzaSize);
}
}

This would produce:

Checking a Radio Button


If you add only one radio button to a container, when the application starts,
the lone radio button would appear with an empty round circle. If the user
clicks that lone radio button, the radio button's circle becomes filled with a
dot and the user cannot remove or change this aspect. If you equip a
container with more than one radio button, the user can click the desired one
to select it and only one of the radio buttons can be selected at a given time.
The radio button that is selected is referred to as checked. To support this
description, the RadioButton class is equipped with a property named
Checked.

At design time, to select a radio button, in the Properties window, set its
Checked property to True. At run time, to programmatically select a radio
button, assign a true value to its Checked property. To find out whether a
particular radio button is selected, get the value of its Checked property. You
can also programmatically check a radio button. Here is an example:
private void Form1_Load(object sender, System.EventArgs e)
{
radioButton2.Checked = true;
}

C# 3.0 Practical Learning II 897


If the user clicks a radio button, since this control is primarily a button, the
radio button that was clicked in the group fires a Click event. This is the
most regularly used event of a radio button. Normally, when the user clicks a
button in the group, the round box of that button becomes filled and the Click
event is fired. If the user clicks a button that is already checked, nothing
changes in the round box of that button but the Click event fires again. In
some cases, you may want to execute code only if the checked state of a
button has actually changed rather than being interested in whether the
button was clicked or not. Fortunately, if you are interested only when the
checked stated of a button is changed, you can use the CheckedChanged
event. This event is fired whenever the checked state of a button is modified.
Here is an example of implementing it:
private void rdoSmall_CheckedChanged(object sender,
System.EventArgs e)
{
txtPizzaPrice.Text = "$8.75";
}

The Alignment of a Radio Button


By default, the round box of a radio button is positioned to the left side of its
accompanying label but you have many options. Besides the left position, you
can position the round box to the top, the right, or the bottom etc side of its
label. The position of the round box with regards to its label is controlled by
the CheckAlign property which is a value of type ContentAlignment. To
specify it at design time, access the Properties window of the radio button
and select the desired value from the CheckAlign field. You can also change
this property programmatically. Here are examples:
private void InitializeComponent()
{
grpPizzaSize = new GroupBox();
grpPizzaSize.Text = "Pizza Size";
grpPizzaSize.Size = new Size(160, 120);
grpPizzaSize.Location = new Point(20, 10);

radSmall = new RadioButton();


radSmall.Text = "Small";
radSmall.CheckAlign = ContentAlignment.TopCenter;
radSmall.Location = new Point(20, 20);

radMedium = new RadioButton();


radMedium.Text = "Medium";
radMedium.CheckAlign = ContentAlignment.TopCenter;
radMedium.Location = new Point(20, 50);

radLarge = new RadioButton();


radLarge.Text = "Large";
radLarge.CheckAlign = ContentAlignment.TopCenter;
radLarge.Location = new Point(20, 80);

C# 3.0 Practical Learning II 898


grpPizzaSize.Controls.Add(radSmall);
grpPizzaSize.Controls.Add(radMedium);
grpPizzaSize.Controls.Add(radLarge);

Controls.Add(grpPizzaSize);
}

Besides the alignment of the check box, you can also control the alignment of
the text with regards to the bounding rectangle of the control. This
characteristic is controlled by the TextAlign property of the RadioButton
class. The TextAlign property also is of type ContentAlignment.

The Appearance of a Radio Button


By default, a radio button appears as a rounded box that gets filled with a big
dot when the user selects it. Optionally, you can make a radio button appear
as a toggle button. Normally, if you make one radio button appear as a
button, you should apply the same characteristics on the other radio buttons
of the same group. The button would appear as a rectangular object. When
the user clicks such a button, it appears down:

If the user clicks another button, this button becomes up:

To change the appearance of a radio button, assign the Button or Normal


value to its Appearance property. The Appearance property is based on the
Appearance enumeration. Here are examples:

private void InitializeComponent()

C# 3.0 Practical Learning II 899


{
grpPizzaSize = new GroupBox();
grpPizzaSize.Text = "Pizza Size";
grpPizzaSize.Size = new Size(150, 120);
grpPizzaSize.Location = new Point(20, 10);

radSmall = new RadioButton();


radSmall.Appearance = Appearance.Button;
radSmall.Location = new Point(20, 20);

radMedium = new RadioButton();


radMedium.Appearance = Appearance.Button;
radMedium.Location = new Point(20, 50);

radLarge = new RadioButton();


radLarge.Appearance = Appearance.Button;
radLarge.Location = new Point(20, 80);

grpPizzaSize.Controls.Add(radSmall);
grpPizzaSize.Controls.Add(radMedium);
grpPizzaSize.Controls.Add(radLarge);

Controls.Add(grpPizzaSize);
}

This would produce:

As you can see, you can apply the Appearance property to a radio button that
does not have a caption. You can also use a caption. If you do, make sure
you align the caption to make is good to see. Here are examples:
private void InitializeComponent()
{
grpPizzaSize = new GroupBox();
grpPizzaSize.Text = "Pizza Size";
grpPizzaSize.Size = new Size(150, 120);
grpPizzaSize.Location = new Point(20, 10);

radSmall = new RadioButton();


radSmall.Text = "Small";
radSmall.Appearance = Appearance.Button;
radSmall.TextAlign = ContentAlignment.MiddleCenter;
radSmall.CheckAlign = ContentAlignment.MiddleCenter;
radSmall.Location = new Point(20, 20);

C# 3.0 Practical Learning II 900


radMedium = new RadioButton();
radMedium.Text = "Medium";
radMedium.Appearance = Appearance.Button;
radMedium.TextAlign = ContentAlignment.MiddleCenter;
radMedium.CheckAlign = ContentAlignment.MiddleCenter;
radMedium.Location = new Point(20, 50);

radLarge = new RadioButton();


radLarge.Text = "Large";
radLarge.Appearance = Appearance.Button;
radLarge.TextAlign = ContentAlignment.MiddleCenter;
radLarge.CheckAlign = ContentAlignment.MiddleCenter;
radLarge.Location = new Point(20, 80);

grpPizzaSize.Controls.Add(radSmall);
grpPizzaSize.Controls.Add(radMedium);
grpPizzaSize.Controls.Add(radLarge);

Controls.Add(grpPizzaSize);
}

This would produce:

If you configure your application and give the user the ability to change the
appearance of the radio button from a round circle to a rectangular object
and vice-versa, and if the user decides to change this appearance, when this
is done, the control whose appearance was changed fires an
AppearanceChanged event. The AppearanceChanged event is of type
EventArgs, meaning that it does not carry any significant information other
than to let you know that the appearance of the button was changed.

Applications:
Compound Interest

Tab Controls and Tab Pages

C# 3.0 Practical Learning II 901


 

Description
As your application becomes crowded with various controls, you may find its
form running out of space. To solve such a problem, you can create many
controls on a form or container and display some of them only in response to
some action from the user. The alternative is to group controls in various
containers and specify when the controls hosted by a particular container
must be displayed. This is the idea behind the concept of property pages. A
property page is a control container that appears as a form or a frame.

A property page can appear by itself. Here is an example labeled Signatures:

In most other cases, a property page appears in a group with other pages. It
functions like a group of pieces of paper placed on top of each other. Each
piece is represented by a tab that allows the user to identify it:

C# 3.0 Practical Learning II 902


To use a property page, the user clicks the header, also called tab, of the
desired page. This brings that page up and sends the other(s) in the
background:

C# 3.0 Practical Learning II 903


If the user needs access to another page, he or she can click the desired tab,
which would bring that page in front and send the previously selected page to
the back.

The pages are grouped and hosted by an object called a property sheet. Like
a form, the property pages of a property sheet are simply used to carry or
hold other controls. The major idea of using a property sheet is its ability to
have many controls available in a relatively smaller area.

Practical Learning: Introducing Tab Controls

1. Start Microsoft Visual C# and create a Windows Application named


Algebra1

2. In the Solution Explorer, right-click Form1.cs and click Rename

3. Type Algebra.cs and press Enter

4. Click the body of the form to select it

5. In the Properties window, change the following characteristics


FormBorderStyle: FixedDialog
Text: Factorial, Permutation, and Combination
Size: 304, 208
StartPosition: CenterScreen
MaximizeBox: False
MinimizeBox: False

6. Save the form

Tab Control Creation


The property pages of a property sheet are also referred to as tab controls.
To support property pages, the .NET Framework provides a class named
TabControl. At design time, to add a property sheet to your application, in
the Containers section of the Toolbox, click TabControl and click the form (or
another container).

To programmatically create a property sheet, declare a variable of type


TabControl, allocate memory for it using the new operator. Like all other
objects, a tab control must have a name. After declaring the variable and
initializing it, add it to the Controls collection of its container.

Here is an example of creating a tab control:


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

C# 3.0 Practical Learning II 904


public class Exercise : System.Windows.Forms.Form
{
TabControl tclPropertySheet;

public Exercise()
{
InitializeComponent();
}

private void InitializeComponent()


{

Text = "Domain Configuration";

Size = new Size(345, 228);


StartPosition = FormStartPosition.CenterScreen;

tclPropertySheet = new TabControl();


tclPropertySheet.Location = new Point(14, 16);
tclPropertySheet.Size = new Size(310, 170);

Controls.Add(tclPropertySheet);
}
}

public class Program


{
static int Main()
{
System.Windows.Forms.Application.Run(new Exercise());
return 0;
}
}

This would produce:

If you want the property sheet to occupy the whole form or to occupy a
section of it, you can specify this using the Dock property.

C# 3.0 Practical Learning II 905


The Tab Pages of a Tab Control
 

Introduction
As mentioned previously, a tab control is made of tabs. These are the actual
objects that make up a tab control. A tab control can have one or more of
them. If you create only a tab control in your application, it is useless and
does not play its intended role. To make it useful, you must add property
pages to it.

Creating a Tab Page


To support property pages, the .NET Framework provides the TabPage
class. Because the property pages completely depend on the tab control, the
TabPage class is not represented in the Toolbox. If you want to add a tab
page to a tab control, the TabControl class is equipped with a property
named TabPages, which is of type TabPageCollection.
TabPageCollection is a collection class that implements the IList, the
ICollection, and the IEnumerable interfaces.

If you create a tab control at design time by taking it from the Toolbox and
adding it to a form, the tab control gets automatically equipped with two
tabs. Here is an example:

At design time, to add a property page, you have various options:

 If the tab control does not yet have any tabs, you can right-click its body
and click Add Tab:

C# 3.0 Practical Learning II 906


 

 If the tab control already has one or more tabs, right-click the right side
to its tabs and click Add Tab
 

 If the tab control already has at least one tab, first select the tab control
(in the next sections, we will learn how to select the tab control). If the
control does not yet have tabs, click its body to select it.

C# 3.0 Practical Learning II 907


When the tab control is selected, click the arrow button on its top-right
side and click Add Tab
 

 While the TabControl control is selected on the form, in the lower


section of the Properties window, you can click the Add Tab link:

 While the TabControl control is selected on the form, in the Properties


window, click the TabPages field and click its ellipsis button to
display the TabPage Collection Editor dialog box that allows you create
and configure each page by clicking its Add button:

C# 3.0 Practical Learning II 908


 

If you create the tab pages at design time, like all other controls, the names
of tab pages are cumulative. As you add them, the first would be named
tabPage1, the second would be named tabPage2, etc. If you plan to
programmatically refer to the tab pages, you should give each a more
meaningful name. As done with any other control, to set the name of a
property page, after selecting it, in the Properties window, change the value
of the (Name) field.

To programmatically create a property page, declare a variable of type


TabPage, allocate memory for it using the new operator, and add it to the
Controls collection of its eventual tab control. Here is an example:

public class Exercise : System.Windows.Forms.Form


{
TabControl tclPropertySheet;
TabPage pgeController;

public Exercise()
{
InitializeComponent();
}

private void InitializeComponent()


{

Text = "Domain Configuration";

C# 3.0 Practical Learning II 909


Size = new Size(345, 228);
StartPosition = FormStartPosition.CenterScreen;

tclPropertySheet = new TabControl();


tclPropertySheet.Location = new Point(14, 16);
tclPropertySheet.Size = new Size(310, 170);

pgeController = new TabPage();


tclPropertySheet.Controls.Add(pgeController);

Controls.Add(tclPropertySheet);
}
}

This would produce:

Alternatively, you can declare a variable of type TabPage, allocate memory


for it using the new operator, and add it to the TabPages collection of its tab
control. Here is an example:
public class Exercise : System.Windows.Forms.Form
{
TabControl tclPropertySheet;
TabPage pgeController;
TabPage pgeAccount;

public Exercise()
{
InitializeComponent();
}

private void InitializeComponent()


{
Text = "Domain Configuration";
Size = new Size(345, 228);
StartPosition = FormStartPosition.CenterScreen;

tclPropertySheet = new TabControl();


tclPropertySheet.Location = new Point(14, 16);
tclPropertySheet.Size = new Size(310, 170);

C# 3.0 Practical Learning II 910


pgeController = new TabPage();
tclPropertySheet.Controls.Add(pgeController);

pgeAccount = new TabPage();


tclPropertySheet.TabPages.Add(pgeAccount);

Controls.Add(tclPropertySheet);
}
}

Practical Learning: Creating Tab Pages

1. Scroll down in the Toolbox to get to the Containers section.


Click TabControl and click the top-left section of the form

2. On the form, right-click the right side of tabPage2 and click Add Page

Removing a Tab Page


If you have added a tab page by mistake or you don't want a particular page
anymore, you can remove it. To remove a property page, first click its tab to
select it. Then,

 You can right-click the TabControl control and click Remove Tab

 You can select the tab control, click the arrow button on its top-right
section and click Remove Tab

 While the undesired tab page is selected on the tab control, you can
press Delete

 While the undesired tab page is selected on the tab control, in the lower
section of the Properties window, you can click the Remove Tab link

 You can right-click the body of the undesired page and click Delete

To programmatically delete a tab control, call the Remove() method of the


TabPages property.

Tab Control and Tab Page Selection


 

C# 3.0 Practical Learning II 911


Tab Control Selection
Many of the effects you will need on pages have to be set on the TabControl
control and not on individual pages. This means that, to manage the
characteristics of pages, you will change the properties of the parent
TabControl control. At any time, whether working on the TabControl
control or on one of its tab pages, you should first know what object you are
working on by selecting it.

To select the TabControl control itself, you have three main options:

 In the top combo box on top of the Properties window, select the name
of the tab control

 Click an unoccupied area on the right side of the most right tab

 While one tab page is selected, click another tab

At run time, neither the user nor you would really need to select a tab
control. On the other hand, with code, you can refer to the tab control using
its name.

Practical Learning: Resizing a Tab Control

1. On the form, click on the right side of tabPage3 to select the tab control.
In the Properties window, click (Name) and type tclAlgebra

2. Click the + button of Location and change its values as follows:


X: 12
Y: 12

3. Click the + button of Size and change its values as follows:


Width: 272
Height: 158

4. Save the form

Tab Page Selection


Before manipulating a tab page, you must first select it. You various options:

 To select a tab page on the form, first click its tab, then click its body

 In the top combo box of the Properties window, select the name of the
desired property page

C# 3.0 Practical Learning II 912


 On the form, click the tab control. In the Properties window, click the
TabPages field and click its ellipsis button. In the Members list of the
TabPage Collection Editor, click the name of the desired tab page

As described in our introduction, to select a property page, the user can click
its tab. To programmatically select a tab page, you have various options.

We mentioned already that the tab pages are added cumulatively. The
application keeps track of their position. To keep track of the positions of
the tab pages, the TabControl class is equipped with a property named
SelectedIndex. Based on this, to select a tab page using its position, assign
the desired index to this property. Here is an example:
private void button1_Click(object sender, EventArgs e)
{
tabControl1.SelectedIndex = 1;
}

You can also call the TabControl.SelectTab() method. In this case, pass
the tab index to the method.

An alternative is to select a tab page using its object name. To support this,
the TabControl class is equipped with the SelectedTab property. Using it,
to select a tab page, assign its name to the SelectedTab property. Here is
an example:
private void button1_Click(object sender, EventArgs e)
{
tabControl1.SelectedTab = tabPage3;
}

You can also call the TabControl.SelectTab() method. In this case, pass
the name of the tab to the method.

Both the TabControl.SelectedIndex and the TabControl.SelectedTab


property are read/write. This means that, besides selecting a property page,
you can use them to find out what tab page is currently selected. To do this,
simply get the value of the control at the time you are accessing it.

Practical Learning: Access a Tab Page

1. On the form, click tabPage1 then click its wide area

2. In the Properties window, click (Name), type tabFactorial and press


Enter

3. In the combo box on top of the Properties window, select tabPage2

4. Click (Name), type tabPermutation and press Enter

C# 3.0 Practical Learning II 913


5. In the combo box on top of the Properties window, select tabPage2

6. Click (Name), type tabCombination and press Enter

7. Save the form

The Tab of a Tab Page


 

Introduction
Like any other visual window, the tab control uses such properties as the the
Location (Right and Top values), the Size (Width and Height values), the
tab stop (TabStop), the tab index (TabIndex), the cursor (Cursor), etc.

After adding the TabControl control to your form and after adding one or
more tab pages, the property pages are created where the TabControl
control is positioned and their dimensions are used by the tab control. This
means that, if you want a different position, a smaller or larger property
sheet, you must modify the dimensions of the TabControl control and not
those of the tab pages, even though each tab page has a Location property
and dimensions (the Size property).

To programmatically find out the location and size of a property sheet, the
TabControl class is equipped with a property named DisplayRectangle
that produces a Rectangle value. Here is an example of using it:
private void Exercise_Load(object sender, EventArgs e)
{
Rectangle rctLocationSize =
tabControl1.DisplayRectangle;
textBox1.Text = rctLocationSize.Left.ToString();
textBox2.Text = rctLocationSize.Top.ToString();
textBox3.Text = rctLocationSize.Width.ToString();
textBox4.Text = rctLocationSize.Height.ToString();
}

The Caption of a Tab


Probably the first obvious characteristic of a tab page is the word or string
that identifies it to the user. That is, the string that displays on the tab of a
property page. This is known as its title or its caption. If you create your tab
pages at design time, by default, the captions are set cumulatively as the

C# 3.0 Practical Learning II 914


pages are added. Usually you will not use these titles because they are
meaningless.

To display a custom title for a property page, on the form, select the tab
control:

 Click the tab of the desired page. In the Properties window, change the
value of the Text property

 In the Properties window, click the ellipsis button of the TagePages field
to open the TabPages Collection Editor. In the Members list, click the
name of the tab page. In the right list, click Text and change the string

To programmatically change the title of a property page, assign a string to its


Text property. Here is an example:

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

public class Exercise : System.Windows.Forms.Form


{
TabControl tclPropertySheet;
TabPage pgeController;

public Exercise()
{
InitializeComponent();
}

private void InitializeComponent()


{

Text = "Domain Configuration";

Size = new Size(345, 228);


StartPosition = FormStartPosition.CenterScreen;

tclPropertySheet = new TabControl();


tclPropertySheet.Location = new Point(14, 16);
tclPropertySheet.Size = new Size(310, 170);

pgeController = new TabPage();


pgeController.Text = "Controller";
tclPropertySheet.Controls.Add(pgeController);

Controls.Add(tclPropertySheet);
}
}

public class Program


{
static int Main()
{

C# 3.0 Practical Learning II 915


System.Windows.Forms.Application.Run(new Exercise());

return 0;
}
}

This would produce:

Practical Learning: Access a Tab Page

1. In the combo box on top of the Properties window, select


tabCombination

2. Click Text and type Combination

3. In the combo box on top of the Properties window, select


tabPermutation

4. Click Text and type Permutation and press Enter

5. In the combo box on top of the Properties window, select tabFactorial

6. Click Text and type Factorial


 

C# 3.0 Practical Learning II 916


7. Save the form

Hot Tracking the Caption of a Tab Page


When the user positions the mouse on a tab, you can (slightly) change the
color of the caption to blue. To support this, the TabControl class is
equipped with the HotTrack Boolean property. Its default value is False. At
design time, to specify this value, select the control and, in the Properties
window, select the desired option of the HotTrack field. To programmatically
set this property, assign the true or false value to the property. Here is an
example:
private void InitializeComponent()
{
Text = "Domain Configuration";
Size = new Size(345, 228);
StartPosition = FormStartPosition.CenterScreen;

tclPropertySheet = new TabControl();


tclPropertySheet.Location = new Point(14, 16);
tclPropertySheet.Size = new Size(310, 170);
tclPropertySheet.HotTrack = true;

pgeController = new TabPage();


pgeController.Text = "Controller";
tclPropertySheet.Controls.Add(pgeController);

Controls.Add(tclPropertySheet);
}

Practical Learning: Hot Tracking the Caption of a Tab


Page

1. In the combo box on top of the Properties window, select tclAlgebra

2. Double-click HotTrack to set its value to True

Padding the Caption of a Tab Page


When you specify the caption of a tab page, the string displays from the left
to the right side of the tab area. If you want, you can specify how much
space should be left empty on the left side of the caption. This space is
referred to as padding. To support this, the TabControl class is equipped with
a property named Padding. The Padding property is of type Point.

During design, to specify the amount of padding, select the tab control on the
form. In the Properties window, click the + button of the Padding field, type

C# 3.0 Practical Learning II 917


the desired amounts of the X and the Y values. To programmatically specify
the padding amount, assign a Point value to the Padding property of your
TabControl object.

The Tool Tip of a Tab Page


A tab is meant to show a relatively short caption that indicates to the user
what the tab page contains. If you want to provide more information, you can
display a more explicit tool tip that would display when the user positions the
mouse on the tab.

To support the tooltips on tabs, the TabControl class is equipped with a


Boolean property named ShowToolTips. Therefore, if you want the tabs to
displays the tool tips, first set this property to True. To show a tool tip on a
tab, select it on the tab control and, in the Properties window, enter a string
in the ToolTipText field.

A Picture on a Tab
Besides, or instead of, the caption, you can display an icon on the tab of one
or more or some selected tabs of your control. To start, you should create an
image list and add some images or icons to it. After creating the image list, to
associate it with the tab control, on the form, select the control. In the
Properties window, click the arrow of the ImageList field and select the image
list.

To specify the image list with code, first create the image list, visually or
programmatically. To associate the image list with the tab control, assign the
name of the image list to the ImageList property of the tab control. Here is an
example:

To visually specify the image to display on a tab:

 On the form, select the desired tab page. In the Properties window, click
ImageIndex and click the arrow of its combo box to select the index of
the picture from the image list

 On the forms, select the tab control. In the Properties window, click the
ellipsis button of the TagePages field to open the TabPages Collection
Editor. In the Members list, click the name of the tab page. In the right
list, click ImageIndex and click the arrow of its combo box to select the
index of the picture

Before programmatically using the images on a tab control, you must first
create an ImageList object and then assign it to the tab control. Here is an
example:
public class Exercise : System.Windows.Forms.Form
{
TabControl tclPropertySheet;

C# 3.0 Practical Learning II 918


ImageList lstImages;

public Exercise()
{
InitializeComponent();
}

private void InitializeComponent()


{
Text = "Domain Configuration";
Size = new Size(345, 228);
StartPosition = FormStartPosition.CenterScreen;

tclPropertySheet = new TabControl();


tclPropertySheet.Location = new Point(14, 16);
tclPropertySheet.Size = new Size(310, 170);
tclPropertySheet.HotTrack = true;

lstImages = new ImageList();

lstImages.Images.Add(Image.FromFile(@"E:\Programs\image1.jpg"));

lstImages.Images.Add(Image.FromFile(@"E:\Programs\Image2.jpg"));

lstImages.Images.Add(Image.FromFile(@"E:\Programs\Image3.jpg"));
tclPropertySheet.ImageList = lstImages;
}
}

After assigning an image list to the tab control, to programmatically specify


the image to display on a tab, assign an index from an ImageList object to
the tab page. To support this, the TabPage class is equipped with a property
named ImageIndex that is of type int. Here is an example:
public class Exercise : System.Windows.Forms.Form
{
ImageList lstImages;
TabPage pgeController;
TabPage pgeAccount;
TabPage pgeSummary;
TabControl tclPropertySheet;

public Exercise()
{
InitializeComponent();
}

private void InitializeComponent()


{
Text = "Domain Configuration";
Size = new Size(345, 228);
StartPosition = FormStartPosition.CenterScreen;

tclPropertySheet = new TabControl();


tclPropertySheet.Location = new Point(14, 16);

C# 3.0 Practical Learning II 919


tclPropertySheet.Size = new Size(310, 170);
tclPropertySheet.HotTrack = true;

lstImages = new ImageList();

lstImages.Images.Add(Image.FromFile(@"E:\Programs\image1.jpg"));

lstImages.Images.Add(Image.FromFile(@"E:\Programs\Image2.jpg"));

lstImages.Images.Add(Image.FromFile(@"E:\Programs\Image3.jpg"));
tclPropertySheet.ImageList = lstImages;

pgeController = new TabPage();


pgeController.Text = "Controller";
pgeController.ImageIndex = 1;
tclPropertySheet.Controls.Add(pgeController);

pgeAccount = new TabPage();


pgeAccount.Text = "Account";
pgeAccount.ImageIndex = 2;
tclPropertySheet.TabPages.Add(pgeAccount);

pgeSummary = new TabPage();


pgeSummary.Text = "Summary";
pgeSummary.ImageIndex = 0;
tclPropertySheet.TabPages.Add(pgeSummary);

Controls.Add(tclPropertySheet);
}
}

Here is an example of what this would produce:

C# 3.0 Practical Learning II 920


Managing the Tabs
 

The Navigation Arrows of a Tab Control


If you have many tab pages and the width of the tab control cannot show all
tabs at the same time, the control would add two navigation arrows to its top
right corner to let the user know that there are more property pages:

A Tab Control With Multi-Line


By default, the navigation buttons would come up because the control uses a
property that controls their availability. If you do not want the navigation
arrows, select the tab control and, in the Properties window, set the
MultiLine property to True. This would create cascading tabs and the user
can simply select the desired property page from its tab:

C# 3.0 Practical Learning II 921


Of course, you can also do this programmatically by assigning the
TabControl.MultiLine to true.

After setting the MultiLine property to true, depending on the number of


tab pages, the control may have 2, 3 or more rows. To find out the number of
rows that the tab control contains, you can get the value of the RowCount
property of the TabControl class. This property is of type int.

The Size Mode


When you specify the caption of a property page, its is resized to
accommodate the string. This means that the tab would get enlarged or
narrowed, depending on the length of  the caption. As an alternative, you can
make all tabs use the same width. To support this, the TabControl class is
equipped with a property named SizeMode. The SizeMode property is based
on the TabSizeMode enumeration that has three members: Normal (the
default), Fixed, and  FillToRight.

To control the size mode at design time, on the form, select the tab control.
In the Properties window, click SizeMode and select the desired option:

Normal: Each tab would be resized to fit its caption:

Fixed: The designer would find out what tab has the longest caption. It
would then use that length as the common width of all the other tabs:

C# 3.0 Practical Learning II 922


If the tab control's MultiLine property is set to true, the designer would get
the length of the longest string of the first (top) row:

 That length would be used as the common length to all the tabs on all rows:

FillToRight: This option is valid only if the MultiLine property is set to


true. With this option, the tabs on each row would be resized so that the total
length of the rows fit the width of the tab control:

C# 3.0 Practical Learning II 923


The Tabs Size
Besides, or in addition to, the size mode, you can control the widths of the
tab by specifying your own width. To do this, first set the SizeMode property
to true. Then, use the ItemSize property of the tab control to specify how
much width you want to apply to all tabs of the control.

The Alignment and Appearance of Tabs

The Alignment of Tabs


As you are adding pages to a TabControl control, the tabs of the pages are
positioned on the top border of the TabControl area. You can reposition them
to the left, the right, or the bottom borders of the control. The placement of
the tab is set using the Alignment property of the TabControl control. The
possible values of this property are Top, Left, Right, and Bottom:
Alignment: Left Alignment: Top

C# 3.0 Practical Learning II 924


Alignment: Bottom Alignment: Right

To support the alignment of the tabs of a property sheet, the TabControl


class is equipped with a property named Alignment. This property is based
on the TabAlignment enumeration and its members are Bottom, Left, Right,
and Top. To programmatically control the alignment of the tabs, assign the
desired value to the tab control. Here is an example:
public class Exercise : System.Windows.Forms.Form
{
TabPage pgeController;
TabPage pgeAccount;
TabControl tclPropertySheet;

public Exercise()
{
InitializeComponent();
}

private void InitializeComponent()


{

C# 3.0 Practical Learning II 925


Text = "Domain Configuration";

Size = new Size(345, 228);


StartPosition = FormStartPosition.CenterScreen;

tclPropertySheet = new TabControl();


tclPropertySheet.Location = new Point(14, 16);
tclPropertySheet.Size = new Size(310, 170);
tclPropertySheet.HotTrack = true;
tclPropertySheet.Alignment = TabAlignment.Left;

pgeController = new TabPage();


pgeController.Text = "Controller";
tclPropertySheet.Controls.Add(pgeController);

pgeAccount = new TabPage();


pgeAccount.Text = "Account";
tclPropertySheet.TabPages.Add(pgeAccount);

Controls.Add(tclPropertySheet);
}
}

The Appearance of the Tabs


If you want to create a discrete property sheet and do not want to display the
traditional tabs, you can replace the tabs with buttons. This is controlled by
the Appearance property that presents three options: Normal (the default),
Buttons, and FlatButtons. The Normal and the Buttons values can be used on
all four views. The FlatButtons option is available only if the Alignment
property is set to Top.
Appearance: Buttons Appearance: FlatButtons

To support the option of showing tabs or buttons, the TabControl class is


equipped with the Appearance property that is based on the TabAppearance

C# 3.0 Practical Learning II 926


enumeration. Therefore, to specify this option, assign the desired value to
your TabControl object. Here is an example:
public class Exercise : System.Windows.Forms.Form
{
TabPage pgeController;
TabPage pgeAccount;
TabPage pgeSummary;
TabControl tclPropertySheet;

public Exercise()
{
InitializeComponent();
}

private void InitializeComponent()


{
Text = "Domain Configuration";
Size = new Size(345, 228);
StartPosition = FormStartPosition.CenterScreen;

tclPropertySheet = new TabControl();


tclPropertySheet.Location = new Point(14, 16);
tclPropertySheet.Size = new Size(310, 170);
tclPropertySheet.HotTrack = true;
tclPropertySheet.Appearance = TabAppearance.FlatButtons;

pgeController = new TabPage();


pgeController.Text = "Controller";
tclPropertySheet.Controls.Add(pgeController);

pgeAccount = new TabPage();


pgeAccount.Text = "Account";
tclPropertySheet.TabPages.Add(pgeAccount);

pgeSummary = new TabPage();


pgeSummary.Text = "Summary";
tclPropertySheet.TabPages.Add(pgeSummary);

Controls.Add(tclPropertySheet);
}
}

Windows Control: The Timer


 

Introduction

C# 3.0 Practical Learning II 927


A timer is a non-spatial object that uses recurring lapses of time in a
computer or in your application. To work, every lapse of period, the control
sends a message to the operating system. The message is something to the
effect of "I have counted the number of lapses you asked me to count".

As opposed to the time that controls your computer, a timer is partly but
greatly under your control. Users do not see nor do they use a timer as a
control. As a programmer, you decide if, why, when, and how to use this
control.

To support timers, the .NET Framework provides the Timer control from the
Toolbox and it is implemented through the Timer class. To add it to your
application at design time, on the Toolbox, click Timer and click the form.

Practical Learning: Introducing the Timer Control

1. Start a new Windows Application named ScreenSaver1

2. Change the following properties of the form:


BackColor: Black
FormBorderStyle: None
WindowState: Maximized

3. In the Properties window, click the Events button and double-click


MouseMove

4. Implement the event as follows:


 
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace ScreenSaver1
{
public partial class Form1 : Form
{
static int MoveCounter = 0;

public Form1()
{
InitializeComponent();
}

private void Form1_MouseMove(object sender,


MouseEventArgs e)

C# 3.0 Practical Learning II 928


{
Cursor.Hide();

if (MoveCounter == 20)
Close();
MoveCounter++;
}
}
}

5. Display the form again and, in the Events section of the Properties
window, double-click KeyDown

6. Implement its event as follows:


 
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
// If the user presses Esc, stop the screen saver
if (e.KeyCode == Keys.Escape)
Close();
}

7. Execute the application to test it (to close the form, you will just move
the mouse or press Esc)

8. Display the form

Characteristics of a Timer
A timer is an object used to count lapses of time and send a message when it
has finished counting. Each count is called a tick. When a tick occurs, the
control fires a Tick event. This Tick event is of type EventArgs, meaning
that it doesn't provide more information than to let you know that a lapse has
occurred.

The amount of time allocated for counting is called an interval and it is


represented by the Interval property. The Interval is a very important
characteristic of the Timer control because it measures and controls the total
time needed to perform a complete count. The Interval is measured in
milliseconds. Like any counter, the lower the value, the faster the count will
finish, and the higher the value, the longer the count (if you ask one kid to
count from 1 to 10 and you ask another to count from 1 to 20 at the same
time, if you ask them to shout when they finish, the first kid would finish first
and would shout first). The amount of interval you specify will depend on
what you are trying to do.

In order for a timer to count, you must tell it when it should start counting. In
some applications, you may want the control to work full-time while in some
other applications, you may want the control to work only in response to an
intermediate event. The ability to stop and start a Timer control can be set
using the Enabled Boolean property. When, or as soon as, this property is set

C# 3.0 Practical Learning II 929


to true, the control starts counting. You can also make it start by calling the
Timer.Start() method. Its syntax is:

public void Start();

If, when, or as soon as, the Enabled property is set to false, the control stops
and resets its counter to 0. You can also stop the timer by calling the
Timer.Stop() method. Its syntax is:

public void Stop();

Practical Learning: Using Timer Controls

1. From the Components section of the Toolbox, click the Timer control
and click the form

2. In the Properties window, set the Enabled property to True and set the
Interval to 200

3. Under the form, double-click the timer

4. In the top section of the file, under the other using System lines, type
using System.Drawing.Drawing2D;

5. Scroll down and implement the Tick event as follows:


 
private void timer1_Tick(object sender, EventArgs e)
{
// Get the Graphics object of the form
Graphics graph = Graphics.FromHwnd(this.Handle);

// Generate a random number


Random rndNumber = new Random(DateTime.Now.Millisecond);

// Create a list of the colors of the .NET Framework


Color[] curColor =
{
Color.AliceBlue, Color.AntiqueWhite, Color.Aqua,
Color.Aquamarine,
Color.Azure, Color.Beige, Color.Bisque, Color.Black,
Color.BlanchedAlmond, Color.Blue,
Color.BlueViolet, Color.Brown,
Color.BurlyWood, Color.CadetBlue,
Color.Chartreuse, Color.Chocolate,
Color.Coral, Color.CornflowerBlue, Color.Cornsilk,
Color.Crimson,
Color.Cyan, Color.DarkBlue, Color.DarkCyan,
Color.DarkGoldenrod,

C# 3.0 Practical Learning II 930


Color.DarkGray, Color.DarkGreen,
Color.DarkKhaki, Color.DarkMagenta,
Color.DarkOliveGreen, Color.DarkOrange, Color.DarkOrchid,
Color.DarkRed, Color.DarkSalmon, Color.DarkSeaGreen,
Color.DarkSlateBlue, Color.DarkSlateGray,
Color.DarkTurquoise,
Color.DarkViolet, Color.DeepPink, Color.DeepSkyBlue,
Color.DimGray,
Color.DodgerBlue, Color.Firebrick, Color.FloralWhite,
Color.ForestGreen,
Color.Fuchsia, Color.Gainsboro, Color.GhostWhite,
Color.Gold,
Color.Goldenrod, Color.Gray, Color.Green,
Color.GreenYellow,
Color.Honeydew, Color.HotPink, Color.IndianRed,
Color.Indigo,
Color.Ivory, Color.Khaki, Color.Lavender,
Color.LavenderBlush,
Color.LawnGreen, Color.LemonChiffon, Color.LightBlue,
Color.LightCoral, Color.LightCyan,
Color.LightGoldenrodYellow,
Color.LightGray, Color.LightGreen, Color.LightPink,
Color.LightSalmon,
Color.LightSeaGreen, Color.LightSkyBlue,
Color.LightSlateGray,
Color.LightSteelBlue, Color.LightYellow, Color.Lime,
Color.LimeGreen,
Color.Linen, Color.Magenta, Color.Maroon,
Color.MediumAquamarine,
Color.MediumBlue, Color.MediumOrchid, Color.MediumPurple,
Color.MediumSeaGreen, Color.MediumSlateBlue,
Color.MediumSpringGreen,
Color.MediumTurquoise, Color.MediumVioletRed,
Color.MidnightBlue,
Color.MintCream, Color.MistyRose, Color.Moccasin,
Color.NavajoWhite,
Color.Navy, Color.OldLace, Color.Olive, Color.OliveDrab,
Color.Orange,
Color.OrangeRed, Color.Orchid, Color.PaleGoldenrod,
Color.PaleGreen,
Color.PaleTurquoise, Color.PaleVioletRed,
Color.PapayaWhip,
Color.PeachPuff, Color.Peru, Color.Pink, Color.Plum,
Color.PowderBlue,
Color.Purple, Color.Red, Color.RosyBrown,
Color.RoyalBlue,
Color.SaddleBrown, Color.Salmon, Color.SandyBrown,
Color.SeaGreen,
Color.SeaShell, Color.Sienna, Color.Silver,
Color.SkyBlue,
Color.SlateBlue, Color.SlateGray, Color.Snow,
Color.SpringGreen,
Color.SteelBlue, Color.Tan, Color.Teal, Color.Thistle,
Color.Tomato,
Color.Transparent, Color.Turquoise, Color.Violet,
Color.Wheat,

C# 3.0 Practical Learning II 931


Color.White, Color.WhiteSmoke, Color.Yellow,
Color.YellowGreen
};

// Create a list of 10 rectangles for each row


Rectangle[] row1 = new Rectangle[10];
Rectangle[] row2 = new Rectangle[10];
Rectangle[] row3 = new Rectangle[10];
Rectangle[] row4 = new Rectangle[10];
Rectangle[] row5 = new Rectangle[10];
Rectangle[] row6 = new Rectangle[10];
Rectangle[] row7 = new Rectangle[10];
Rectangle[] row8 = new Rectangle[10];

// Create the rectangles that will be drawn on the


screen
for (int i = 0; i < 9; i++)
{
row1[i] = new Rectangle(i + (i * (Width / 10)),
0,
(Width - 36) / 10, Height / 8);

row2[i] = new Rectangle(i + (i * (Width / 10)),


4 + (Height / 8),
(Width - 36) / 10, Height / 8);

row3[i] = new Rectangle(i + (i * (Width / 10)),


8 + (2 * (Height / 8)),
(Width - 36) / 10, Height / 8);

row4[i] = new Rectangle(i + (i * (Width / 10)),


12 + (3 * (Height / 8)),
(Width - 36) / 10, Height / 8);

row5[i] = new Rectangle(i + (i * (Width / 10)),


16 + (4 * (Height / 8)),
(Width - 36) / 10, Height / 8);

row6[i] = new Rectangle(i + (i * (Width / 10)),


20 + (5 * (Height / 8)),
(Width - 36) / 10, Height / 8);

row7[i] = new Rectangle(i + (i * (Width / 10)),


24 + (6 * (Height / 8)),
(Width - 36) / 10, Height / 8);

row8[i] = new Rectangle(i + (i * (Width / 10)),


28 + (7 * (Height / 8)),
(Width - 36) / 10, Height / 8);
}

// Create the last rectangle of each row


Rectangle row1a = new Rectangle(9 + (9 * (Width / 10)),
0, ((Width - 36) / 10) - 2,
Height / 8);
Rectangle row2a = new Rectangle(9 + (9 * (Width / 10)),

C# 3.0 Practical Learning II 932


4 + (Height / 8), ((Width - 36) / 10) -
2, Height / 8);
Rectangle row3a = new Rectangle(9 + (9 * (Width / 10)),
8 + (2 * (Height / 8)), ((Width -
36) / 10) - 2, Height / 8);
Rectangle row4a = new Rectangle(9 + (9 * (Width / 10)),
12 + (3 * (Height / 8)), ((Width -
36) / 10) - 2, Height / 8);
Rectangle row5a = new Rectangle(9 + (9 * (Width / 10)),
16 + (4 * (Height / 8)), ((Width
- 36) / 10) - 2, Height / 8);
Rectangle row6a = new Rectangle(9 + (9 * (Width / 10)),
20 + (5 * (Height / 8)), ((Width
- 36) / 10) - 2, Height / 8);
Rectangle row7a = new Rectangle(9 + (9 * (Width / 10)),
24 + (6 * (Height / 8)), ((Width
- 36) / 10) - 2, Height / 8);
Rectangle row8a = new Rectangle(9 + (9 * (Width / 10)),
28 + (7 * (Height / 8)), ((Width
- 36) / 10) - 2, Height / 8);

// Create a list of the hatch brushes of the .NET


Framework using random colors
HatchBrush[] curBrush =
{
new HatchBrush(HatchStyle.BackwardDiagonal,

curColor[rndNumber.Next(curColor.Length)],

curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.Cross,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.DarkDownwardDiagonal,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.DarkHorizontal,
curColor[rndNumber.Next(curColor.Length)],

curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.DarkUpwardDiagonal,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.DarkVertical,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.DashedDownwardDiagonal,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.DashedHorizontal,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.DashedUpwardDiagonal,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.DashedVertical,

C# 3.0 Practical Learning II 933


curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.DashedVertical,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.DiagonalBrick,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.DiagonalCross,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.Divot,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.DottedDiamond,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.DottedGrid,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.ForwardDiagonal,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.Horizontal,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.HorizontalBrick,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.LargeCheckerBoard,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.LargeConfetti,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.LargeGrid,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.LightDownwardDiagonal,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.LightHorizontal,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.LightUpwardDiagonal,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.LightVertical,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.Max,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.Min,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),

C# 3.0 Practical Learning II 934


new HatchBrush(HatchStyle.NarrowHorizontal,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.NarrowVertical,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.OutlinedDiamond,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.Percent05,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.Percent10,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.Percent20,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.Percent25,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.Percent30,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.Percent40,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.Percent50,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.Percent60,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.Percent70,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.Percent75,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.Percent80,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.Percent90,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.Plaid,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)]),
new HatchBrush(HatchStyle.Percent05,
curColor[rndNumber.Next(curColor.Length)],
curColor[rndNumber.Next(curColor.Length)])
};

// Draw the rectangles to cover the screen


for (int i = 0; i < 9; i++)
{

C# 3.0 Practical Learning II 935


graph.FillRectangle(curBrush[rndNumber.Next(curBrush.Length)],
row1[i]);
graph.DrawRectangle(new
Pen(curBrush[rndNumber.Next(curBrush.Length)]), row1[i]);

graph.FillRectangle(curBrush[rndNumber.Next(curBrush.Length)],
row2[i]);
graph.DrawRectangle(new
Pen(curBrush[rndNumber.Next(curBrush.Length)]), row2[i]);

graph.FillRectangle(curBrush[rndNumber.Next(curBrush.Length)],
row3[i]);
graph.DrawRectangle(new
Pen(curBrush[rndNumber.Next(curBrush.Length)]), row3[i]);

graph.FillRectangle(curBrush[rndNumber.Next(curBrush.Length)],
row4[i]);
graph.DrawRectangle(new
Pen(curBrush[rndNumber.Next(curBrush.Length)]), row4[i]);

graph.FillRectangle(curBrush[rndNumber.Next(curBrush.Length)],
row5[i]);
graph.DrawRectangle(new
Pen(curBrush[rndNumber.Next(curBrush.Length)]), row5[i]);

graph.FillRectangle(curBrush[rndNumber.Next(curBrush.Length)],
row6[i]);
graph.DrawRectangle(new
Pen(curBrush[rndNumber.Next(curBrush.Length)]), row6[i]);

graph.FillRectangle(curBrush[rndNumber.Next(curBrush.Length)],
row7[i]);
graph.DrawRectangle(new
Pen(curBrush[rndNumber.Next(curBrush.Length)]), row7[i]);

graph.FillRectangle(curBrush[rndNumber.Next(curBrush.Length)],
row8[i]);
graph.DrawRectangle(new
Pen(curBrush[rndNumber.Next(curBrush.Length)]), row8[i]);
}

graph.FillRectangle(curBrush[rndNumber.Next(curBrush.Length)],
row1a);
graph.DrawRectangle(new
Pen(curBrush[rndNumber.Next(curBrush.Length)]), row1a);

C# 3.0 Practical Learning II 936


graph.FillRectangle(curBrush[rndNumber.Next(curBrush.Length)],
row2a);
graph.DrawRectangle(new
Pen(curBrush[rndNumber.Next(curBrush.Length)]), row2a);

graph.FillRectangle(curBrush[rndNumber.Next(curBrush.Length)],
row3a);
graph.DrawRectangle(new
Pen(curBrush[rndNumber.Next(curBrush.Length)]), row3a);

graph.FillRectangle(curBrush[rndNumber.Next(curBrush.Length)],
row4a);
graph.DrawRectangle(new
Pen(curBrush[rndNumber.Next(curBrush.Length)]), row4a);

graph.FillRectangle(curBrush[rndNumber.Next(curBrush.Length)],
row5a);
graph.DrawRectangle(new
Pen(curBrush[rndNumber.Next(curBrush.Length)]), row5a);

graph.FillRectangle(curBrush[rndNumber.Next(curBrush.Length)],
row6a);
graph.DrawRectangle(new
Pen(curBrush[rndNumber.Next(curBrush.Length)]), row6a);

graph.FillRectangle(curBrush[rndNumber.Next(curBrush.Length)],
row7a);
graph.DrawRectangle(new
Pen(curBrush[rndNumber.Next(curBrush.Length)]), row7a);

graph.FillRectangle(curBrush[rndNumber.Next(curBrush.Length)],
row8a);
graph.DrawRectangle(new
Pen(curBrush[rndNumber.Next(curBrush.Length)]), row8a);
}

6. Execute the application

The Forms of an Application:


Introduction
 

Introduction
The form is the most fundamental object used in an application. By itself, a
form does nothing. Its main role is to host other objects that the user uses to
interact with the computer:

C# 3.0 Practical Learning II 937


 

Form Creation
There are various ways you can get a form to your application:

 If you create a Windows Forms Application, it creates a starting form for


you

 After starting an empty project or a Windows Forms Application, you can


add a form to it. To do this, on the main menu, you can click Project ->
Add New Item... Select Windows Form. Give it a name and click OK

 You can dynamically create a form and add it to your application.

In Lesson 2, we saw that a was based on the Form class that is defined in the
System.Windows.Forms namespace created in the
System.Windows.Forms.dll assembly. Therefore, if you start an application
from scratch and you want to use a form in it, you can include the
System.Windows.Forms.dll library to your application. To refer to a form,
you can include the System.Windows.Forms namespace in your application.

As seen in Lesson 2, to create a form-based application, you can derive a


class from Form. Here is an example:
public class Exercise : System.Windows.Forms.Form
{
private void InitializeComponent()
{
}

public Exercise()

C# 3.0 Practical Learning II 938


{
InitializeComponent();
}
}

public class Program


{
static int Main()
{
System.Windows.Forms.Application.Run(new Exercise());
return 0;
}
}

Practical Learning: Introducing Forms

1. Start Microsoft Visual C# and create a new Windows Application named


CPAS1

2. Press Ctrl + F5 to test the program

3. Close the form and return to your programming environment

The Name of a Form


Like any other control, a form must have a name. If you derive a class from
Form, the name you use for the class would be the name of the form. If you
add a form from the Add New Item dialog box, you must also give it a name.
If you create a Windows Application from the New Project dialog box, the
wizard would create a default form for you named Form1. However you
create or get a form, you can change its name.

To change the name of a form, in the Solution Explorer, right-click the name
of the form and type a new name with the .cs extension.

Practical Learning: Renaming a Form

1. In the Solution Explorer, right-click Form1.cs and click Rename

2. Type Central.cs and press Enter

The Forms of an Application:


The Title Bar

C# 3.0 Practical Learning II 939


 

The System Icon


A form is made of various sections that allow its control as a Windows object and other
aspects that play a valuable part as a host of other objects. The top section of a form is
made of a long portion called the title bar.

On the left side of the title bar, the form displays a small picture called an icon or the
system icon. Microsoft Visual Studio 2005 provides a default icon for all forms. If you
want to use a different icon, while the form is selected, in the Properties window, you can
click the Icon field and then click its ellipsis button . This would launch the Open dialog
box from where you can locate an icon and open it.

To change the icon programmatically, declare a variable of type Icon of the


System.Drawing namespace and initialize it with the name of an icon file
using the new operator. After initializing the icon, assign it to the form's Icon
property. Here is an example:
private void InitializeComponent()
{
System.Drawing.Icon customIcon =
new
System.Drawing.Icon(@"C:\Programs\RedBook.ico");
Icon = customIcon;
}

Whether you had assigned an icon to the for or not, you can control whether
the form should display an icon. To support this, the Form class is equipped
with a Boolean property named ShowIcon. If you set this property to false,
the icon would not appear in the title bar of the form. If the Form.ShowIcon
property is set to true, which is its default value, the form's title bar would
display an icon.

Practical Learning: Configuring a Form's Title Bar

1. On the main menu, click Project -> Add New Item...

2. In the Templates list, click Icon File

3. Set the Name to cpas click Add

C# 3.0 Practical Learning II 940


4. Design the icon as follows:
 

5. To continue with the icon design, on the main menu, click Image ->
New Image Type...

6. On the New Icon Image Type, click 16x16, 256 colors line:
 

7. Click OK

8. Design it as follows:
 

9. To save the icon, on the Standard toolbar, click the Save All button

10. Close the window tab that contains the icon designed

C# 3.0 Practical Learning II 941


11. Click the body of the form to make sure it is selected. In the Properties
window, click Icon and click its ellipsis button

12. On the Open dialog box, locate the folder in which you had saved the
project and select the cpas icon
 

13. Click Open


 

14. Execute the application to test it

15. Close it and return to your programming environment

The Form's Caption


On the right side of the system icon, there is a word or a group of words
called the caption. By default, the caption displays the name of the form. If
you want to change the caption, while the form is selected, in the Properties
window, click the Text field and type anything you want. After typing the
text, press Enter to display it on the form.

C# 3.0 Practical Learning II 942


At design time, the caption is made of text that you type "as is". At run time,
you can change the caption to display a more complex text that could be a
changing time, the result of a calculation, etc. Here is an example:
private void InitializeComponent()
{
Icon = new
System.Drawing.Icon(@"C:\Programs\RedBook.ico");
Text = "Windows Fundmentals - Programming";
}

This would produce:

Practical Learning: Setting a Form's Caption

1. While the form is selected, in the Properties window, click Text and type
College Park Auto Shop - Customer Repair Order

2. Press Enter

The System Buttons


On the right side of the caption, there are three small buttons called the
system buttons, made of the Minimize ( , , or ), the Maximize ( ,
, or ), and the Close ( , , or ) buttons. The presence or absence
of these buttons is controlled by the Boolean ControlBox property whose
default value is True to indicate that the form will be equipped with the
system buttons. If you set it to False, no system button would be displayed:

C# 3.0 Practical Learning II 943


In this case, the user would not be able to close the form using the system
buttons. Therefore, if you create this type of form, make sure you provide the
user with a way to close it.

The Minimize ( , , or ) button is controlled by a Boolean property


called MinimizeBox. By default, when you freshly create a form, this property
is set to True and the form would display a Minimize button.

The Maximize ( , , or ) button is controlled by the Boolean


MaximizeBox property, which also is set to True by default. Depending on
what you are trying to achieve in your application, you can change the value
of either one or both of these properties. The four combinations are as follows:

MaximizeBox MinimizeBox Display Result

The form can be


True True minimized or
maximized

The form can be


True False maximized but cannot
be minimized

The form can be


False True minimized but cannot
be maximized 

False False The form can be


neither minimized nor

C# 3.0 Practical Learning II 944


maximized

To change a system button programmatically, call the desired button's


property and assign it a true or false value. Here is an example that makes
sure the user cannot maximize the form:
private void InitializeComponent()
{
Icon = new
System.Drawing.Icon(@"C:\Programs\RedBook.ico");
Text = "Windows Fundmentals - Programming";

ControlBox = true;
MinimizeBox = true;
MaximizeBox = false;
}

This would produce:

Practical Learning: Configuring a Form's System


Buttons

1. To make sure that the user cannot maximize the form, on the Properties
window, click the MaximizeBox field to reveal its combo box and select
False

2. Test the program


 

C# 3.0 Practical Learning II 945


3. Close the form and return to your programming environment

The Forms of an Application:


The Form's Position
 

The Form's Location


When you create an application and while you are designing the form, it is fixed in the
top-left corner of the Form Designer. This is not the position the form would have when
it runs. In fact, by default, a random position is set for the form when it comes up.
Fortunately, you can specify where the form would be located when it comes up and you
have various alternatives.

Like every control on an application, a form has a parent: the desktop. The
desktop is the wide area of the monitor easily seen when the computer
comes up. Everything on the computer is located with regards to this main
parent. In the same way, a form uses the desktop to determine its "physical"
location. Based on this, when an application is launched, its form occupies an
area of the desktop. To locate its children, the desktop uses a Cartesian
coordinate system whose origin is located on the top-left corner of the
screen:

C# 3.0 Practical Learning II 946


The horizontal measurements move from the origin to the right. The vertical
measurements move from the origin to the bottom:

The distance from the the desktop’s left border to the form’s left border is
represented by the form's Left property. The distance from the desktop’s top
border to the form’s top border is specified by the Top property. Therefore,

C# 3.0 Practical Learning II 947


the Left and the Top values are known as the form’s location. This can be
illustrated as follows:

To specify the default location of a form when the application is opened, in


the Properties window, click the + button of the Location field to reveal the
values of the location. If a value of a property is set to 0, the compiler would
select a random value for it when the form comes up. Otherwise, you can
change each value to a valid natural number.

If you want to programmatically set the location of the form, you can assign a
value to its Left and/or its Top properties. Here is an example:
public class Exercise : System.Windows.Forms.Form
{
public Exercise()
{
InitializeComponent();
}

private void InitializeComponent()


{
Icon = new
System.Drawing.Icon(@"C:\Programs\RedBook.ico");
Text = "Windows Fundmentals - Programming";

Left = 228;
Top = 146;
}

C# 3.0 Practical Learning II 948


}

Alternatively, you can assign a Point variable to the form's Location


property. Here is an example:
private void InitializeComponent()
{
Icon = new
System.Drawing.Icon(@"C:\Programs\RedBook.ico");
Text = "Windows Fundmentals - Programming";

Location = new System.Drawing.Point(228, 146);


}

The Startup Position of a Form


At design time, the X and Y values of the Location property allow you to
specify a position for the form. At run time, the Left and Top properties
accomplish the same purpose. Microsoft Windows provides an alternative
position to specify the location of the form relative to its parent. This is the
role of the StartPosition property of the Form class, which is a value of the
FormStartPosition enumerator. It provides the following five values:

Value Result

The form will be positioned in the center of its parent. If the


CenterParent application is made of only one form, this form would be
positioned in the middle of the desktop

CenterScreen The form will be positioned in the middle of the desktop even if
this form is part of an application that is made of various forms.

The form will use the values of the X, Y, Left, and/or Top
Manual
properties of the Location

WindowsDefaultLocation
The operating system will specify the form's position using a
value known in Win32 as CW_USEDEFAULT

Based on this, to set the default relative location of a form when it comes up,
change the value of its StartPosition combo box in the Properties window.
To specify this characteristic when programmatically creating a form or to
change this property at run time, call the FormStartPosition enumeration
to select the desired value and assign it to the StartPosition property of
the form. Here is an example:
using System;
using System.Windows.Forms;

C# 3.0 Practical Learning II 949


public class Exercise : System.Windows.Forms.Form
{
public Exercise()
{
InitializeComponent();
}

private void InitializeComponent()


{
Icon = new
System.Drawing.Icon(@"C:\Programs\RedBook.ico");
Text = "Windows Fundmentals - Programming";

StartPosition =
FormStartPosition.WindowsDefaultLocation;
}
}

The StartPosition property provides another value that is related to the


size. Therefore, we will mention it when we review the size of a form.

Practical Learning: Setting a Form's Default Position

1. Click the middle of the form to make sure it is selected

2. In the Properties window, click StartPosition to reveal its combo box.


Click the arrow of its combo box and select CenterScreen

3. Execute the application to view the result. Notice that it is centered on


the screen

4. Close it and return to your programming environment

The Window State of a Form


When creating your application, you can configure its (main) form to be
minimized or maximized when the application is launched. This feature is
controlled by the WindowState property. The default value of this property is
Normal which means the form would appear in the same dimensions it was
designed. If you want the form to be minimized or maximized at startup, in
the Properties window, change the desired value of the WindowState
property to Maximized or Minimized.

To control the window’s state programmatically, assign the Maximized or


Minimized value, which are members of the FormWindowState enumerator,
to the WindowState property. Here is an example:
using System;
using System.Drawing;

C# 3.0 Practical Learning II 950


using System.Windows.Forms;

public class Exercise : System.Windows.Forms.Form


{
public Exercise()
{
InitializeComponent();
}

private void InitializeComponent()


{
Icon = new Icon(@"C:\Programs\RedBook.ico");
Text = "Windows Fundmentals - Programming";

WindowState = FormWindowState.Maximized;
}
}

If you want to check the state of a window before taking action, simply use a
conditional statement to compare its WindowState property with the Normal,
the Maximized, or the Minimized values.

The Form's Taskbar Presence


When an application displays on the screen along with other applications, its
form can be positioned on top of, or behind, forms of other applications. This
is allowed by multitasking assignments. When a form is hidden, the taskbar
allows you to access it because the form would be represented by a button.
This aspect of forms is controlled by the ShowInTaskbar Boolean property.
Its default value is True, which indicates that the form would be represented
on the taskbar by a button.

If you create an application made of various forms, you may not want to
show all of its forms on the taskbar. Usually the first or main form would be
enough. To prevent a button for a form to display on the taskbar, set its
ShowInTaskbar property to False.

Here is an example:
private void InitializeComponent()
{
Icon = new Icon(@"C:\Programs\RedBook.ico");
Text = "Windows Fundmentals - Programming";

ShowInTaskbar = false;
}

Unless you have a good reason, and it is hard to see what that reason
could be, you should not set the ShowInTaksbar property of the first or
main form of an application to false.

C# 3.0 Practical Learning II 951


The Forms of an Application:
The Form's Measures
 

The Form's Size


A form's size is the amount of space it is occupying on the screen. It is
expressed as its width and its height. The width of a form is the distance from
its left to its right borders. The height is the distance from the top to the
bottom borders of a form:

When you create a form, it assumes a default size. To set or change the size
of a form, at design time, first click it to select it. Then, position the mouse on
its right, bottom, or bottom-right handles. This changes the mouse cursor in
one of three shapes:

C# 3.0 Practical Learning II 952


With the mouse positioned, drag in the desired direction.

If you don't want to be able to resize a form and you want to prevent this by
accident, at design time, set the form's Locked property to True. If you do
this:

 A small picture of a lock displays in the top-left corner of the form:

 The form gets surrounded by a rectangle with a black border

 The sizing handles of the form disappear

Because Locked is only a design characteristic, it is not an actual


property of the Form class. Therefore, you cannot use it to lock a form
at run time. In order words, you cannot use the Lock feature to prevent
the user from resizing a form.

Besides resizing the form by dragging one of its handles, to change the size
of a form, select it and, in the Properties window, click the + button of the

C# 3.0 Practical Learning II 953


Size field. Then type the desired value for the Width and the desired value
for the Height. The values must be natural numbers.

To programmatically change the size of a form, assign the desired values to


either or both its Width and Height properties. Here is an example:
private void InitializeComponent()
{
Icon = new Icon(@"C:\Programs\RedBook.ico");
Text = "Windows Fundmentals - Programming";

Width = 425;
Height = 308;
}

Alternatively, you can assign a Size value to the Size property of the form.
Here is an example:
private void InitializeComponent()
{
Icon = new Icon(@"C:\Programs\RedBook.ico");
Text = "Windows Fundmentals - Programming";

Size = new Size(425, 308);


}

If you want the operating system to specify the size of the form, set its
StartPosition property to WindowsDefaultBounds. In this case, a value
called CW_USEDEFAULT would be assigned to both the Width and the Height
properties.

Practical Learning: Setting the Form's Default Size

1. Position the mouse to the small square on the right border of the form

2. Click and drag in the right direction to make sure the caption in the title
bar can appear completely

C# 3.0 Practical Learning II 954


 

3. Release the mouse

The Form Borders


A form can be made to look like a regular rectangular host made of a system
icon and the system buttons. Depending on your goals, you can also make a
form appear as a dialog box or a dockable window. The borders of a form are
controlled by the FormBorderStyle property.

If you set both the MinimizeBox and the MaximizeBox properties to False,
we saw that the form would have only the system Close button, but the form
can still be resized. If you want the form to display only the system Close
button and to prevent the user from resizing it, set its FormBorderStyle
property to FixedDialog. Here is an example:
private void InitializeComponent()
{
Icon = new Icon(@"C:\Programs\RedBook.ico");
Text = "Windows Fundmentals - Programming";

FormBorderStyle = FormBorderStyle.Fixed3D;
}

This would produce:

C# 3.0 Practical Learning II 955


A tool window is a form equipped with a short title
bar, no icon, and only a small system Close button.
There are two types of tool windows.

 A tool window is referred to as fixed if the user


cannot resize it. In this case, the
FormBorderStyle property of the form is set to
FixedToolWindow:
 
FormBorderStyle =
FormBorderStyle.FixedToolWindow;

 A tool window is referred to as sizable if it allows


the user to resize it. To get such a form, set its
FormBorderStyle property to
SizableToolWindow:
 
FormBorderStyle =
FormBorderStyle.SizableToolWindow;

You can also create a form with no borders by


assigning None to the FormBorderStyle property. If
you do this, make sure you provide the user with a
way to close the form; otherwise...

C# 3.0 Practical Learning II 956


The Forms of an Application:
The Client Area of a Form
 

Introduction
When a form has been created, you can add Windows controls to it. These
controls can be positioned only in a specific area, the body of the form. The
body spans from the left border of the form, excluding the border itself, to
the right border of the form, excluding the border. It also spans from the top
side, just under the title bar, to the bottom border, excluding the bottom
border, of the form. The area that the form makes available to the controls
added to it is called the client area:

If a control is positioned on a form, its location uses a coordinate system


whose origin is positioned on the top-left section of the client area (just under
the title bar). The x axis moves from the origin to the left. The y axes moves
from the origin down:

C# 3.0 Practical Learning II 957


The distance from the left border of the client area to the left border of the
control is the Left property. The distance from the top border of the client
area to the top border of the control is the Top property. These can be
illustrated as follows:

To know the amount of space that a form is making available to its child
control, you can access the form's ClientSize property.

The Background Color of a Form


The client area of a form is painted with a color specified by the operating
system. To change the color to anything you like, you can use the BackColor
field of the Properties window. If you click the arrow of its combo box, it displays
a property sheet with three tabs that divide the color in categories:

C# 3.0 Practical Learning II 958


To programmatically change its color, assign a color from the Color structure
to the BackColor property. Here is an example:
public class Exercise : System.Windows.Forms.Form
{
public Exercise()
{
InitializeComponent();
}

private void InitializeComponent()


{
Icon = new Icon(@"C:\Programs\RedBook.ico");
Text = "Windows Fundmentals";

BackColor = Color.BurlyWood;
}
}

This would produce:

C# 3.0 Practical Learning II 959


If you look closely, you will notice that only the client area of the form is
painted. The borders, since they are not part of the client area, are not
painted.

The Forms of an Application:


The Background Image of a Form
 

Introduction
If you prefer to cover the client area with a picture, use the
BackgroundImage property instead. To specify the background picture at
design time, in the Properties window, click BackgroundImage and click its
ellipsis button. This would open the Select Resource dialog box. To locate a
picture, click one of the Import buttons, select the picture from the chosen
folder and click Open. The picture would be imported in the dialog box:

You can then select it and click OK 

C# 3.0 Practical Learning II 960


To programmatically specify or change the picture used as background,
declare and initialize a pointer to the Bitmap class. Then assign it to the
BackgroundImage property. Here is an example:

private void InitializeComponent()


{
Icon = new Icon(@"C:\Programs\RedBook.ico");
Text = "A Day at the Beach";
MaximizeBox = false;

BackgroundImage =
Image.FromFile(@"E:\Programs\beach.jpg");
}

Background Image Options


There are two ways you can use a background image on a form. You can fill
the whole client area with the picture if the picture is bigger than the client
area. If the picture is narrower and/or shorter than the picture, you can resize
or repeat it. To assist you with making this decision, the Form class is
equipped with a property named BackgroundImageLayout.

The Form.BackgroundImageLayout property is based on the ImageLayout


enumeration. Its values are:

C# 3.0 Practical Learning II 961


 None: The picture will display once, from the top-left origin of the client
area of the form. Here is an example:
 
private void InitializeComponent()
{
Icon = new Icon(@"C:\Programs\RedBook.ico");
Text = "Fire Wall";
MaximizeBox = false;

BackgroundImage =
Image.FromFile(@"E:\Programs\FireWall.png");
BackgroundImageLayout = ImageLayout.None;
}

 Center: The picture will display once, in the middle-center of the client
area of the form. Here is an example:
 
private void InitializeComponent()
{
Icon = new Icon(@"C:\Programs\RedBook.ico");
Text = "Fire Wall";
MaximizeBox = false;

BackgroundImage =
Image.FromFile(@"E:\Programs\FireWall.png");
BackgroundImageLayout = ImageLayout.Center;
}

C# 3.0 Practical Learning II 962


 Tile: The picture will start displaying from the top-left origin of the
client area. Then it will repeat itself horizontally, followed by the next
line, then the next, and so on. Here is an example:
 
private void InitializeComponent()
{
Icon = new Icon(@"C:\Programs\RedBook.ico");
Text = "Fire Wall";
MaximizeBox = false;

BackgroundImage =
Image.FromFile(@"E:\Programs\FireWall.png");
BackgroundImageLayout = ImageLayout.Tile;
}

C# 3.0 Practical Learning II 963


 Stretch: The picture will first be positioned in the middle of the client
area of the form, then it will stretch itself to occupy the whole client
area, and so on. Here is an example:
 
private void InitializeComponent()
{
Icon = new Icon(@"C:\Programs\RedBook.ico");
Text = "Fire Wall";
MaximizeBox = false;

BackgroundImage =
Image.FromFile(@"E:\Programs\FireWall.png");
BackgroundImageLayout = ImageLayout.Stretch;
}

C# 3.0 Practical Learning II 964


 Zoom: The compiler will find out which measure is smaller between the
width and the height of the client area of the form. That smaller measure
will be used for both the width and the height of the picture. Here is an
example:
 
private void InitializeComponent()
{
Icon = new Icon(@"C:\Programs\RedBook.ico");
Text = "Fire Wall";
MaximizeBox = false;

BackgroundImage =
Image.FromFile(@"E:\Programs\FireWall.png");
BackgroundImageLayout = ImageLayout.Zoom;
}

 If the form's width is lower than its height, then the picture will be
positioned in the middle of the form:

C# 3.0 Practical Learning II 965


 If the form's height is lower than its width, then the picture will be
positioned in the center of the form:

Methods and Events to Manage a Form

Form Creation
The form is implemented by the Form class from the System.Windows.Forms
namespace. The Form class is equipped with a constructor that allows you to
dynamically create it. After a form has been created, it must be loaded to
display on the screen. When a form is being loaded, it fires the Load() event
which is of type EventArgs. This event is fired when a form is about to be
displayed for the first time. Therefore, it can be used to perform last minute
initializations.

C# 3.0 Practical Learning II 966


Form Activation
When two or more forms are running on the computer, only one can receive
input from the user. This means that only one form can actually be directly
used at one particular time. Such a window has a title bar with the color
identified in Control Panel as Active Window. The other window(s), if any,
display(s) its/their title bar with a color called Inactive Window.

To manage this setting, the windows are organized in a 3-dimensional


coordinate system and they are incrementally positioned on the Z coordinate,
which defines the (0, 0, 0) origin on the screen (on the top-left corner of the
monitor) with Z coordinate coming from the screen towards you.

In order to use a form other than the one that is active, you must activate it.
To do this, you can call the Activate() method. Its syntax is:
public void Activate();

When a form is activated, it fires the Activated event, which is an


EventArgs type of event.

Form Deactivation
If there is more than one form or application on the screen, only one can be
in front of the others and be able to receive input from the others. If a form is
not active and you want to bring it to the top, you must activate it, which
fires the Activated() event. When a form is being activated, the one that
was on top would become deactivated. The form that was on top, as it looses
focus, would fire the Deactivate() event which is an EventArgs type.

Form Closure
When the user has finished using a form, he or she must be able to close it.
Closing a form is made possible by a simple call to the Close() method. Its
syntax is:
public void Close();

When this method is called, the process of closing a form starts. At this time,
the Closing() event is fired. The Closing() event is implemented by the
CancelEventArgs class through the CancelEventHandler delegate. The
CancelEventArgs class is equipped with only the Cancel property. The
CancelEventArgs.Cancel property allows you to cancel or to continue with
the closing of the form. If you set the CancelEventArgs.Cancel property to
true, the event will be ignored as if it were not fired. If you want the event
to continue closing the form, you can set this property to false. This event
occurs before the form is actually closed, giving you time to let the form be
closed, prevent the form from being closed, or take any other necessary
action.

C# 3.0 Practical Learning II 967


After a form has been closed, a Closed() event is fired. Although this
method can be used to close any form of an application, if it is called by the
main form, it also closes the application.

Dialog Boxes
 

Description
A dialog box is a form defined with particular properties. Like a form, a dialog
box is referred to as a container. Like a form, a dialog box is mostly used to
host child controls, insuring the role of dialog between the user and the
machine. Here is an example of a dialog box:

A dialog box has the following characteristics:

 The only system button it is equipped with is Close . As the only


system button, this button allows the user to dismiss the dialog and
ignore whatever the user would have done on the dialog box

 It cannot be minimized, maximized, or restored. A dialog box does not


have any other system button but Close

 It is usually modal, in which case the user is not allowed to continue any
other operation on the same application until the dialog box is
dismissed

 It provides a way for the user to close or dismiss it

C# 3.0 Practical Learning II 968


Practical Learning: Introducing Dialog Boxes

1. Start Microsoft Visual C# and create a new Windows Application named


SolasPropertyRental1

2. From the Common Controls section of the Toolbox, click ListView and
click the form

3. While the list view is still selected, in the Properties window, change the
following characteristics
(Name): lvwProperties
View: Details

4. Still in the Properties window, click Columns and click its ellipsis button

5. In the ColumnHeader Collection Editor, click Add

6. In the right list, click Text and type Property #

7. Click Add.
In the right list, click Text and type Property Type

8. Click Add.
In the right list, click Text and type Bedrooms

9. Click Add.
In the right list, click Text and type Bathrooms

10. Click Add.


In the right list, click Text and type Monthly Rent

11. Click OK

12. Complete the design of the form as follows:


 

Control Text Name

C# 3.0 Practical Learning II 969


ListView    

Button New Property... btnNewProperty

Button Close btnClose

13. To add another form to the project, on the main menu, click Project ->
Add Windows Form...

14. In the Templates list, make sure Windows Form is selected.


Set the Name to PropertyEditor and click Add

Dialog Box Creation


To create a dialog box, you start with a form, which you can get by creating a
Windows Application or deriving a class from Form. Here is an example:
using System;
using System.Drawing;
using System.Windows.Forms;

public class Exercise : System.Windows.Forms.Form


{
public Exercise()
{
InitializeComponent();
}

private void InitializeComponent()


{

Text = "Domain Configuration";

Width = 320;
Height = 150;
Location = new Point(140, 100);
StartPosition = FormStartPosition.CenterScreen;
}
}

public class Program


{
static int Main()
{
System.Windows.Forms.Application.Run(new Exercise());
return 0;
}
}

This would produce:

C# 3.0 Practical Learning II 970


 

Characteristics of Dialog Boxes


 

The Border Style of a Dialog Box


There are a few actions you should perform on a form to transform it into a
dialog box; but normally, these are only suggestions, not rules. Based on the
Microsoft Windows design and standards, to create a dialog box, you should
set a form’s FormBorderStyle property to FixedDialog. Setting this
property changes the borders of the form to the standard borders of a dialog
box (the border of a dialog box is thinner than that of a regular form). You
can set this characteristic in the Properties window or programmatically.

Here is an example:
private void InitializeComponent()
{

Text = "Domain Configuration";

Width = 320;
Height = 150;
Location = new Point(140, 100);
StartPosition = FormStartPosition.CenterScreen;

FormBorderStyle = FormBorderStyle.FixedDialog;
}

The Minimize and Maximize Boxes


Besides taking care of the border, you should also set both the MinimizeBox
and the MaximizeBox properties to False. This causes the window to display

C# 3.0 Practical Learning II 971


only the system Close button. You can set these characteristics in the
Properties window or programmatically. Here is an example:
private void InitializeComponent()
{
Text = "Domain Configuration";
Width = 320;
Height = 150;
Location = new Point(140, 100);
StartPosition = FormStartPosition.CenterScreen;

FormBorderStyle = FormBorderStyle.FixedDialog;
MinimizeBox = false;
MaximizeBox = false;
}

This would produce:

Practical Learning: Configuring a Dialog Box

1. To transform the PropertyEditor form into a dialog box, in the Properties


window, change its characteristics as follows:
FormBorderStyle: FixedDialog
StartPosition:        CenterParent
MinimizeBox:         False
MaximizeBox:        False
ShowInTaskbar:    False

2. Design the dialog box as follows:


 

C# 3.0 Practical Learning II 972


Control Text Name

Label Property Type:  

TextBox   txtPropertyType

Button Cancel btnCancel

Label Bedrooms:  

TextBox   txtBedrooms

Button OK btnOK

Label Bathrooms:  

TextBox   txtBatrooms

Label Monthly Rent:  

TextBox   txtMonthlyRent

Closing a Dialog Box


You should provide a way for the user to close the dialog box. A dialog box
should have at least one button labeled OK. This button allows the user to
acknowledge the message of the dialog box and close it by clicking the
button. If the user press Enter, the dialog box should also be closed as if the
OK button was clicked.

Accepting an Action
Often the user will be presented with various options on a dialog box and may
be asked to make a decision on the available controls. Most of the time, if you
are creating such a dialog box, besides the OK button, it should also have a
Cancel button. The OK button should be the default so that if the user
presses Enter, the dialog box would be closed as if the user had clicked OK.
Clicking OK or pressing Enter would indicate that, if the user had made
changes on the controls of the dialog box, those changes would be

C# 3.0 Practical Learning II 973


acknowledged and kept when the dialog box is closed and usually the
changed values of the control would be transferred to another dialog box or
form. Keep in mind that you are responsible for implementing this
functionality.

To fulfill this functionality of the OK button, after adding it to a dialog box (or
form), open the AcceptButton combo box in the Properties window for the
form and select the name of the button.

Practical Learning: Accepting an Action

1. Click an unoccupied area of the form

2. In the Properties window, click the arrow of the AcceptButton field and
select btnOK

Cancelling an Action
The Cancel button is used to allow the user to dismiss whatever changes
would have been made on the controls of the dialog box. The dialog box
should also be configured so that if the user presses Esc, the dialog box
would be closed as if the user had clicked Cancel.

To fulfill this functionality of the Cancel button, after adding it to a dialog box
(or form), open the CancelButton combo box in the Properties window for
the form and select the name of the button.

Besides the OK and the Cancel buttons, a dialog box can be created with
additional buttons such as Finish or Help, etc. It depends on its role and the
decision is made by the application developer.

Practical Learning: Cancelling an Action

1. In the Properties window, click the arrow of the CancelButton field and
select btnCancel
 

2. Display the first form

C# 3.0 Practical Learning II 974


The Help Button
Besides the system Close button, if you are planning to provide help on a
dialog box, you can equip it with a Help button. To support this, the Form
class is equipped with a Boolean property named HelpButton. The default
value of this property is false. In the Properties window, you can set it to
True. If you are programmatically creating the dialog box, you can access this
property and set its value to true. Here is an example:
private void InitializeComponent()
{
Text = "Domain Configuration";
Width = 320;
Height = 150;
Location = new Point(140, 100);
StartPosition = FormStartPosition.CenterScreen;

FormBorderStyle = FormBorderStyle.FixedDialog;
MinimizeBox = false;
MaximizeBox = false;

HelpButton = true;
}

This would produce:

When the user clicks the help button, the mouse cursor becomes equipped
with a question mark. Here is an example:

C# 3.0 Practical Learning II 975


You can then write code so that, when the user clicks a control on the dialog
box, some guiding help is provided as a tool tip.

Modal and Modeless Dialog Boxes


 

Modal Dialog Boxes


There are two types of dialog boxes: modal and modeless.

A Modal dialog box is one that the user must first close in order to have
access to any other framed window or dialog box of the same application.
One of the scenarios in which you use a dialog box is to create an application
that is centered around one. In this case, if either there is no other form or
dialog box in your application or all the other forms or dialog boxes depend
on this central dialog box, it must be created as modal. Such an application is
referred to as dialog-based.

Some applications require various dialog boxes to complete their functionality.


When in case, you may need to call one dialog box from another and display
it as modal. Here is an example:

The Date and Time dialog box of WordPad is modal: when it is displaying, the
user cannot use any other part of WordPad unless he or she closes this object
first

C# 3.0 Practical Learning II 976


After creating a dialog used as an addition to an existing form or an existing
dialog box, to call it as modal, use the ShowDialog() method.

Modeless Dialog Boxes


A dialog box is referred to as modeless if the user does not have to close it in
order to continue using the application that owns the dialog box. A modeless
dialog box has the following characteristics

 It has a thin border

 It can be neither minimized nor maximized. This means that it is not


equipped with the Minimize or the Maximize buttons

 It is not represented on the taskbar with a button

 It must provide a way for the user to close it

Here is an example:

The Find
(and the
Replace)
dialog box of
WordPad
(also the Find
and the

C# 3.0 Practical Learning II 977


Replace
dialog boxes
of most
applications)
is an example
of a modeless
dialog box. If
it is opened,
the user does
not have to
close it in
order to use
the
application or
the document
in the
background.

Since the modeless dialog box does not display its button on the task bar, the
user should know that the dialog box is opened. To make the presence of a
modeless dialog box obvious to the user, it typically displays on top of its host
application until the user closes it.

A modeless dialog box is created from a form but it should look like a regular
dialog box or a tool window. Therefore, to create a modeless dialog box, set
the FormBorderStyle property to an appropriate value such as
FixedSingle, FixedToolWindow, Sizable or SizableToolWindow. Also,
set its ShowInTaskbar property to False.

After creating the dialog box, to display it as modeless, call the Show()
method. The fundamental difference between the ShowDialog() and the
Show() methods is that the former displays a modal dialog box, which makes
sure that the called dialog box cannot go in the background of the main
application. By contrast, the Show() method only calls the dialog box every
time it is requested. For this reason, it is up to you to make sure that the
modeless dialog box always remains on top of the application. This is easily
taken care of by setting the Boolean TopMost property of the form to True.

There are two main ways a normal modeless dialog box can be dismissed:

 If the user has finished using it, he or she can close it and recall it at will
 When the form or application that owns the modeless dialog box is closed, the
form or application closes the modeless dialog if it is opened; this means that
you don't need to find out whether a modeless dialog box is still opened when
the application is being destroyed: either the user or the application itself will
take care of closing it

C# 3.0 Practical Learning II 978


An Application With Various Forms or Dialog boxes
When you create a Windows Forms Application, the starting form is made
available to you. If one form is not enough for your application, you can add
as many as necessary. To add (or to create) a (new) form, you have various
options:

 On the main menu, you can click Project -> Add New Item...

 On the main menu, you can click File -> Add New Item...

 In Solution Explorer, you can right-click the name of the project, position
the mouse on Add, and click Add New Item...

In the Add New Item dialog box and in the Templates section, click Window
Form (.NET), provide a name in the Name edit box then click Open.

If your application is using various forms and you want to display a particular
one at design time:

 In the Forms Designer, you can click the tab that corresponds to the
desired form and that has [Design]

 On the main menu, you can click Window and click the name of the form
in the list under Close All Documents

 In Solution Explorer, expand the Header Files node if necessary and


double-click the name of the desired form that has the .h extension

If you visually add two (or more) forms to your application, you may need to
link them, allow one to call the other. To do this, in the top section of the file,
type #include followed by the name of the header file in which the form was
defined. In the section where you want to access the form, declare a handle
to the class of the form and use the new operator to allocate memory for it.
To display the other form, you can call its Show() method.

Practical Learning: Using Various Forms


1. Display the first form

2. Double-click the New Property... button and implement the event as follows:
 
private void btnNewProperty_Click(object sender,
EventArgs e)
{
Random rnd = new Random();
PropertyEditor dlgEditor = new
PropertyEditor();

if (dlgEditor.ShowDialog() ==

C# 3.0 Practical Learning II 979


DialogResult.OK)
{
ListViewItem lvi =
lvwProperties.Items.Add(
rnd.Next(100000,
999999).ToString());

lvi.SubItems.Add(dlgEditor.txtPropertyType.Text);

lvi.SubItems.Add(dlgEditor.txtBedrooms.Text);

lvi.SubItems.Add(dlgEditor.txtBathrooms.Text);

lvi.SubItems.Add(dlgEditor.txtMonthlyRent.Text);
}
}

3. Execute the application and click the New Property... button

4. Create a property
 

5. Press Enter

6. Create a few more properties and press Enter each time


 

C# 3.0 Practical Learning II 980


7. Close it and return to your programming environment

Message Boxes
 

Introduction
A message box is a special dialog box used to display a piece of information to the user.
As opposed to a regular form, the user cannot type anything in the dialog box. The .NET
Framework inherently supports message boxes through its own MessageBox class.
Besides this, you can also use functions from either the Visual Basic or the Win32
libraries.

C# 3.0 Practical Learning II 981


The Return Value of a Message Box
Besides displaying a message, a message box is may be meant to let the user make a
decision by clicking a button and, depending on the button the user would have clicked,
the message box would return a value.

The value returned by a message box corresponds to the particular button


the user would have clicked (on the message box). The return values are
defined in the DialogResult enumeration. The buttons and the returned values
are as follows:

If the User
The Method Returns
Clicks

DialogResult.Abort

DialogResult.Cancel

DialogResult.Ignore

DialogResult.No

DialogResult.OK

DialogResult.Retry

DialogResult.Yes

The Message of a Message Box


The .NET Framework provides the MessageBox class function used to easily
create a message box. To display a simple message with just an OK button,
you can call the Show() static method of this class. Its syntax is as follows:
public static DialogResult MessageBox.Show(string message);

In this case, the message to display must be passed as a string to the Show()
method. Here is an example:

C# 3.0 Practical Learning II 982


public class Program
{
static int Main()
{
MessageBox.Show("Welcome to the Wonderful World of
Visual C#");
return 0;
}
}

This would produce:

The message to display can be made of up to 1024 characters. To display the


message on multiple lines, you can use the new line escape sequence anywhere
inside the string.

The Caption of a Message Box


In reality, the MessagBox.Show() method is overloaded with various
versions. Another version is:
public static DialogResult Show(string text, string caption);

This version allows you to specify a custom caption for the message box. With
this version, the first argument is the string that the user will see displaying
on the message box. You can pass it as a string. You can also create it from
other pieces of strings.

The second argument, caption, will be the sentence to display in the title bar
of the message box. Here is an example:
public class Program
{
static int Main()
{
MessageBox.Show("Welcome to the Wonderful World of
Visual C#",
"Visual C#
Tutorials");
return 0;
}
}

This would produce:

C# 3.0 Practical Learning II 983


The Buttons of a Message Box
Another version of the MessageBox.Show() method is as follows:
public static DialogResult Show(string text,
string caption,
MessageBoxButtons buttons);

This version allows you to display one or more buttons on the message box.
The available buttons are defined through the MessageBoxButtons
enumeration. Its members are:

MessageBoxButtons  Display

OK

OKCancel

YesNo  

YesNoCancel

RetryCancel

AbortRetryIgnore

To use any of these combinations of buttons, call the MessageBoxButtons


enumeration and access the desired combination. Here is an example:
public class Program
{
static int Main()
{
MessageBox.Show("Welcome to the Wonderful World of
Visual C#",
"Visual C# Tutorials",
MessageBoxButtons.OKCancel);

C# 3.0 Practical Learning II 984


return 0;
}
}

This would produce:

The Icon of a Message Box


This version allows you to display an icon. The possible icons are available
through the MessageBoxIcon enumeration. The members of this enumerator
are:

MessageBoxIcon Description

None  

Asterisk

Error

Exclamation

Hand

Information 

Question

Stop

Warning

C# 3.0 Practical Learning II 985


Here is an example:
public class Program
{
static int Main()
{
MessageBox.Show("Your order appears to be correct" +
"\nAre you ready to provide your credit
card information?",
"Customer Order Processing",
MessageBoxButtons.YesNoCancel,
MessageBoxIcon.Information);
return 0;
}
}

This would produce:

The Default Button of a Message Box


When a message box is configured to display more than one button, the
operating system is set to decide which button is the default. The default
button has a thick border that sets it apart from the other button(s). If the
user presses Enter, the message box would behave as if the user had clicked
the default button. If the message box has more than one button, you can
decide what button would be the default. To specify the default button, the
MessageBox.Show() method provides the following version:

public static DialogResult Show(string text,


string caption,
MessageBoxButtons buttons,
MessageBoxIcon icon,
MessageBoxDefaultButton
defaultButton);

Based on this, you can specify the default button using the last argument that
provides values through the MessageBoxDefaultButton enumerator whose
values are:

Button1: The left button will be the default. Here is an example:


public class Program
{
static int Main()
{

C# 3.0 Practical Learning II 986


MessageBox.Show("Your order appears to be correct" +
"\nAre you ready to provide your credit
card information?",
"Customer Order Processing",
MessageBoxButtons.YesNoCancel,
MessageBoxIcon.Information,
MessageBoxDefaultButton.Button1);
return 0;
}
}

Button2: If the message box displays two buttons, the right button will be the
default. If the message box displays three buttons, the middle button will be
the default. Here is an example:
public class Program
{
static int Main()
{
MessageBox.Show("Your order appears to be correct" +
"\nAre you ready to provide your credit
card information?",
"Customer Order Processing",
MessageBoxButtons.YesNoCancel,
MessageBoxIcon.Information,
MessageBoxDefaultButton.Button2);
return 0;
}
}

Button3: The right button will be the default. Here is an example:


public class Program
{
static int Main()
{
MessageBox.Show("Your order appears to be correct" +

C# 3.0 Practical Learning II 987


"\nAre you ready to provide your credit
card information?",
"Customer Order Processing",
MessageBoxButtons.YesNoCancel,
MessageBoxIcon.Information,
MessageBoxDefaultButton.Button3);
return 0;
}
}

The Code Editor


 

Introduction
There are two main ways you will manipulate an object of your application, visually or
using code. In future sections, we will explore details of visually designing a control. As
you should have found out from learning C#, code of an application is ASCII text-based,
written in plain English and readable to human eyes. For an application, you can use any
text editor to write your code but one of Visual Studio's main strengths is the code
editor. It is very intuitive.

The Code Editor is a window specially designed for code writing.

Although all languages of the Visual Studio programming environment


share the Code Editor, once you have started a type of application,
the Code Editor is adapted to the language you are using. Its parser
(a program used internally to analyze your code) behaves according
to the language of your choice. The features and behaviors of the
Code Editor are also different, depending on your language.

C# 3.0 Practical Learning II 988


To display the code editor, in the Solution Explorer, you can click the View
Code button .

The Code Editor is divided in 4 sections:

Practical Learning: Introducing the Code Editor


1. To create a new class, on the main menu, click Project -> Add Class...

2. Set the Name to Circle and click Add

The Tabs Bar


The top section of the Code Editor displays tabs of property pages. Each tab
represents a file. To add a new file to the project, on the main menu, you can
click

 File -> New -> File...

 Project -> Add New Item...

Once in the Add New Item dialog box, in the Templates section, click the type
of file you want to create, type a name in the Name text box, and press
Enter. After the file has been created, it is represented by a tab in the top

C# 3.0 Practical Learning II 989


section of the Code Editor. In the same way, you can add as many files as
you judge them necessary. To access a tab:

 You can click its name in the Tabs Bar

 On the main menu, you can click Window and click the name of the
desired tab
By default, the tabs display in the order their files were created or added to the
project, from left to right. If you don't like that arrangement, click and drag its
tab either left or right beyond the next tab

Practical Learning: Introducing the Code Editor


1. To create a new class, on the main menu, click Project -> Add Class...

2. Set the Name to Square and click Add

3. To create a new class, on the main menu, click Project -> Add Class...

4. Set the Name to Triangle  and click Add

5. To access the Circle tab, on the main menu, click Window -> Circle

6. Change the file as follows:


 
using System;

namespace Exercise1
{
class Circle
{
private double rad;

public double Radius


{
get { return rad; }
set { rad = value; }
}

public double Area


{
get { return rad * rad * Math.PI; }
}
}

class Sphere : Circle


{
public new double Area
{
get { return 4 * Radius * Radius * Math.PI; }
}

C# 3.0 Practical Learning II 990


}

class Cylinder : Circle


{
private double hgt;

public double Height


{
get { return hgt; }
set { hgt = value; }
}
}
}

7. To access another tab, in tabs section, click Triangle

8. Change the file as follows:


 
using System;

namespace Exercise1
{
class Triangle
{
private double bas;
private double hgt;

public double Base


{
get { return bas; }
set { bas = value; }
}

public double Height


{
get { return hgt; }
set { hgt = value; }
}
}

class Kite
{
}
}

9. Save all

The Types Combo Box


The top-left section of the Code Editor displays a combo box named Types.
As its name indicates, the Types combo box holds a list of the types as
classes and structures that are used in the current project. You can display
the list if you click the arrow of the combo box:

C# 3.0 Practical Learning II 991


Each item of the Types combo box displays the name of its type associated
with its parent as implemented in the code. The parent can be a class or a
namespace. If you select a class in the list, the Code Editor jumps to that
class and positions the caret at the beginning of the class' definition.

Practical Learning: Using the Types Combo Box

1. Click the Circle tab

2. In the Types combo box, select Exercise1.Circle

The Members Combo Box


The top-right section of the Code Editor displays a combo box named
Members. The Members combo box holds a list of the members of classes.
The content of the Members combo box depends on the item that is currently
selected in the Types combo box. This means that, before accessing the
members of a particular class, you must first select that class in the Types
combo box. Then, when you click the arrow of the Members combo box, the
members of only that class display:

If you select an item from the Members combo box, the Code Editor jumps to
that members and positions the cursor to the left of the member.

Practical Learning: Using the Members Combo Box

1. In the Members combo box, select Area

C# 3.0 Practical Learning II 992


2. Press the up arrow key and add a Diameter property
 
using System;

namespace Exercise1
{
class Circle
{
private double rad;

public double Radius


{
get { return rad; }
set { rad = value; }
}

public double Diameter


{
get { return rad * 2; }
}

public double Area


{
get { return rad * rad * Math.PI; }
}
}

. . . No Change
}

3. Save all

Code Colors
Code is written in a wide area with a white background. This is the area you
use the keyboard to insert code with common readable characters. The
Code Editor uses some colors to differentiate categories of words or lines of
text. The colors used are highly customizable. To change the colors, on the
main menu, you can click Tools -> Options... In the Options dialog box, in the
Environment section, click Fonts and Colors. To set the color of a category, in
the Display Items section, click the category. In the Item Foreground combo
box, select the desired color. If you want the words of the category to have a
colored background, click the arrow of the Item Background combo box and
select one:

C# 3.0 Practical Learning II 993


In both cases, the combo boxes display a fixed list of colors. If you want more
colors, you can click a Custom button to display the Color dialog box that allows
you to "create" a color.

Regions
When code of a file is long, it can be tiresome to scroll up and down. The
Visual Studio .NET's Code Editor allows you to create sections that allow the
code to behave like the tree arrangement of the left pane of Windows
Explorer. This means that you can expand or collapse section of code. The
Code Editor supports this feature automatically by adding + buttons at the
beginning of the lines of sections that can be expanded or collapsed. This is
the case for namespaces, classes, methods, interfaces, properties, etc. The
end of an expandable section displays a - button to the beginning of the line.

Besides the default sections that the Code Editor is intuitively aware of, you
can create your own region. A region must have a beginning and an end. To
specify the start of a section, type #region. You can optionally add a label to
the right of #region to name the region. After creating a region with
#region, the Code Editor adds a + button to its left. To expand a region, you
can click its + button. This changes it into a - button. To collapse the region,
click the - button.

If you don't specify the end of the region, the code from #region to the end
of the file would be considered as belonging to the to the region. Therefore,
you should specify the end of the region you created. To mark the end of the
region, in the desired line, type #endregion.

C# 3.0 Practical Learning II 994


Here are examples of regions:
using System;

namespace GeometricFormulas
{
interface IGeometry
{
double Length { get; set; }
double Height { get; set; }
}

class Square
{
#region Formulas to Calculate a Square's Perimeter
and Area
public double Perimeter(double side)
{
return side * 4;
}

public double Area(double side)


{
return side * side;
}
#endregion
}

class Trapezoid
{
private double _base1;
}

class Rectangle : IGeometry


{
private double len;
private double hgt;

public Rectangle()
{
this.len = 0.00;
this.hgt = 0.00;
}

public Rectangle(double L, double H)


{
this.len = L;
this.hgt = H;
}

#region IGeometry Members

public double Length


{
get
{

C# 3.0 Practical Learning II 995


// TODO: Add Rectangle.Length getter
implementation
return len;
}
set
{
// TODO: Add Rectangle.Length setter
implementation
len = value;
}
}

public double Height


{
get
{
// TODO: Add Rectangle.Height getter
implementation
return hgt;
}
set
{
// TODO: Add Rectangle.Height setter
implementation
hgt = value;
}
}

#endregion

public double Perimeter


{
get { return (len + hgt) * 2; }
}

public double Area


{
get { return len * hgt; }
}
}

The Code Editor can help you specify the beginning and end of a region.

C# 3.0 Practical Learning II 996


Methods and Events of
Windows Controls
 

Fundamentals of Controls Methods

Introduction
A method is a procedure created as a member of a class. Methods are used
to access or manipulate the characteristics of an object or a variable. There
are mainly two categories of methods you will use in your classes:

 If you are using a control such as one of those provided by the Toolbox,
you can call any of its public methods. The requirements of such a
method depend on the class being used

 If none of the existing methods can perform your desired task, you can
add a method to a class.

Control's Construction and Destruction


As you know from your study of the C# language, every class has a
fundamental method called a default constructor. Every control of the .NET
Framework is based on a class that has a default constructor and most of
those classes have only one constructor: the default. The default constructor
allows you to instantiate the class without necessarily initializing it. To use it,
you must know the name of the control you want to use since each control
bears the same name as its class. Here is an example:
using System;
using System.Windows.Forms;

public class Exercise : System.Windows.Forms.Form


{
private Button btnReset;

public Exercise()
{
InitializeComponent();

C# 3.0 Practical Learning II 997


}

#region Section Used to Initialize Controls


private void InitializeComponent()
{
btnReset = new Button();
}
#endregion

static void Main()


{

Application.Run(new Exercise());
}
}

If you are not planning to use a control straight from the .NET Framework,
you can also create your own class that is derived from the class of the
control, as we have mentioned in previous lessons. 

As mentioned in the previous lesson, after instantiating a control, it is


available but the user cannot see. Each control that acts as a parent of
another control has a property called Controls. This property, which is a
ControlCollection type, is equipped with an Add() method. If you want to
display the new control to the user, you should pass it to the
Control.Controls.Add() method. Here is an example:

using System;
using System.Windows.Forms;

public class Exercise : System.Windows.Forms.Form


{
private Button btnReset;

public Exercise()
{
InitializeComponent();
}

#region Section Used to Initialize Controls


private void InitializeComponent()
{
btnReset = new Button();
Controls.Add(btnReset);
}
#endregion

static void Main()


{
Application.Run(new Exercise());
}
}

This displays the control to the user.

C# 3.0 Practical Learning II 998


After using a control, it must be destroyed. In C++, this is traditionally done
using the delete operator in the destructor of the parent of all controls,
which could be a form. Another detail of Windows controls is that they use or
consume computer resources during their lifetime. When the controls are not
used anymore, such as when their application closes, these resources should
be freed and given back to the operating system to make them available to
other controls. This task can be performed using the Dispose() method to
the Control class, which can then be overridden by its child controls. The
syntax of the Control.Dispose() method is:
protected override void Dispose(bool disposing);

This method takes one argument, disposing, that indicates how the resources
would be released. If this argument is passed with a false value, only the
unmanaged resources would be released. If it is passed as true, then both
managed and unmanaged resources would be released.

Control's Visibility
In the previous lesson, we saw that you can call the Visible property to hide
a visible control or to display a hidden control. Besides the Visible property,
you can also display a control using the Show() method. Its syntax is:
Public Sub Show()

When you use this method, if the control is visible, nothing would happen. If
it were hidden, then it would be revealed. In the following example, a text
box named textBox1 is asked to display:
private void button1_Click(object sender, EventArgs e)
{
this.textBox1.Visible = false;
}

private void button2_Click(object sender, EventArgs e)


{
this.textBox1.Show();
}

The Show() method internally sets the Visible property to true. We also
saw that, to hide a control, you can set its Visible property to False. In the
same way, to hide a control, you call can the Control.Hide() method. Its
syntax is:
Public Sub Hide()

In the following example, the visibility of a text box named textBox1 is


toggled by the user clicks a button named button1:
private void button1_Click(object sender, EventArgs e)
{
if( this.textBox1.Visible == true )

C# 3.0 Practical Learning II 999


this.textBox1.Hide();
else
this.textBox1.Show();
}

Keep in mind that hiding a control does not close or destroy it.

Control's Focus
Once a control is visible, the user can use it. Some controls allow the user
only to read their text or view what they display. Some other controls allow
the user to retrieve their value or to change it. To perform such operations,
the user must first give focus to the control. The focus is a visual aspect that
indicates that a control is ready to receive input from the user. Various
controls have different ways of expressing that they have received focus.

Button-based controls indicate that they have focus by drawing a dotted


rectangle around their caption. In the following picture, the button on the
right has focus:

A text-based control indicates that it has focus by displaying a blinking cursor.


A list-based control indicates that it has focus when one of its items has a
surrounding dotted rectangle:

To give focus to a control, the user can press a key such as Tab. To
programmatically give focus to a control, call the Focus() method. Here is an
example:
private void button2_Click(object sender, EventArgs e)
{
this.textBox1.Focus();
}

C# 3.0 Practical Learning II 1000


The Z-Order of Controls
In the previous lesson, we saw how you can position controls visually or
manually. In some cases, you end up with one control positioned on top of
another. Of course the first remedy that comes in mind would consist of
moving one of the controls away from the other. This would also imply
sometimes that you would have to enlarge and/or heighten the controls'
container. There are situations that either you don't want to resize the parent
or you can't: your only solution is to have one control on top of another.
Fortunately, you can cope with this situation by specifying, when needed,
what control at what time should be displayed to the user.

When one control is positioned on top of another, they use a third axis whose
origin, like that or the other axes, is on the top-left corner of the parent. This
third axis, also considered the z-axis, is oriented so that it moves from the
monitor towards the user. The operating system is in charge of positioning
and drawing the objects on the screen. You as the programmer can direct the
operating system as to what object should be on top and what object should
be behind. To support these changes the Control class uses two methods
that its appropriate children derive also.

When a control A is positioned behind a control be, this causes control be


either partially or completely hidden. If you want the control A to change its
z-order and become on top of control B, you can call its BringToFront()
method. The syntax of this method is:
public void BringToFront();

On the other hand, if a control B is positioned on top of a control A, if you


want control B to become positioned behind control A, you can call control B's
SendToBack() method. Its syntax is:

public void SendToBack();

After the controls have been positioned, at any time, when you access a
control, if you want to know whether that control is the most top object, you
can call its GetTopLevel() method. Its syntax is:
proteced bool GetTopLevel();

Creating New Methods


The Windows controls available from the .NET Framework and that we will
user throughout this site are fully functional. They are equipped with various
methods ready to be used. Of course, no library can surely provide every
single type of method that every programmer would use. For this reason, it
will not be unusual that you need a method that is not available for a control
you are using. In the same way, when you create a Windows Application that
is based on a Form class, you will likely need a method that is not defined in
the Form class. In this case, you can create your own and new method.

C# 3.0 Practical Learning II 1001


A method is created like a normal procedure. If you want to add it to a form,
you can open the Code Editor and write your procedure outside of any
existing procedure. Here is an example:
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.Run(new Form1());
}

double CalculateRectangleArea(Rectangle Recto)


{
return Recto.Width * Recto.Height;
}
}
}

In the same way, if you derive a class from one of the existing classes
because you want to get a custom control from it, you can declare a new
method as you see fit and use it appropriately.

Probably the best way is to let the Code Editor insert the new method based
on your specifications. To do that, in the Class View, first expand the name of
the project. Then, right-click the name of the class where you want to add a
new method, position the mouse on Add, and click Add Method. This would
open the C# Method Wizard dialog box you can fill out and click Finish. After
the method's body has been defined you

Using External Libraries

Introduction
The Windows controls featured in the .NET Framework are highly varied and
provide all the necessary regular functionality a normal application would
need. They do this through various properties and their different methods. To
enhance their functionality and speed up application development, you can
either create your own new library or use a library created in another
language.

Microsoft Visual Basic Functions


Microsoft Visual Basic offers a very large set of functions.  You can use most
of those functions in your application if you follow the appropriate steps. To
use a Microsoft Visual Basic function in your application, you must reference
its library. Most (if not all) of the functions of Visual Basic are created in the

C# 3.0 Practical Learning II 1002


Microsoft.VisualBasic.dll assembly but they might be in different
namespaces. Based on this, you can include any Visual Basic function in your
program. Here is an example:

Using a Library
If the .NET Framework doesn't have a class you are looking for, you can
create one and be able to use it over and over again in different programs.
You can even create a commercial class and be able to distribute or sell it. To
make this possible, you can "package" one or more classes in a library. A
library is a program that contains classes and/or other resources that other
programs can use. Such a program is created with the same approach as the
programs we have done so far. Because a library is not an executable, it
doesn't need the Main() function. A library usually has the extension .dll.

A library can be made of a single file or as many files as necessary. A file that
is part of a library can contain one or more classes. Each class should
implement a behavior that can eventually be useful and accessible to other
classes. The classes in a library are created exactly like those we have used
so far. Everything depends on how you compile it.

To create a library, start by typing its code in a text file. Once the library is
ready, to compile it, at the Command Prompt, you would type:

csc /target:library NameOfFile.cs

and press Enter. After doing this, a library with the name of the file and the
extension .dll would be created. If you want a custom name, use the
following syntax:
csc /target:library /out:DesiredNameOfLibrary.dll NameOfFile.cs

Using a Visual C++/CLI Library


One of the most important sought goals in .NET is to allow different
languages to collaborate, such as sharing code. One way this can happen is
to be able to use the functionality of one language into another. As an
illustration, we saw earlier that you could use the rich library of Visual Basic
functions in a C# application. As no library is ever complete, you may still
need functionality that is not easily found. Furthermore, you may be working
with a team of C++ programmers who have already created a set of
functions or complex operations. You should be able to use that existing
code.

In previous years, it used to be a challenge to create a library, especially in


C++. Fortunately, Microsoft Visual C++ now makes it particularly easy to
create one, because a wizard highly assists you. To create a library, first
display the New Project dialog box. After specifying Visual C++, in the

C# 3.0 Practical Learning II 1003


Templates list, click Class Library and give it a name. In the body of the file,
you can create the classes and/or functions as you see fit.

Using the Win32 Library


The Microsoft Windows operating system was originally written in C, the
parent language of C++ and C# (also of Java and JavaScript). To allow
programmers to create applications, Microsoft released a library called Win32.
This is a series of functions and classes, etc, that you previously had to use.
As time has changed, you don't need to exclusively use Win32 anymore to
create a Windows application. Nonetheless, Win32 is still everywhere and it is
not completely avoidable because many or some of the actions you would
want to perform in a Windows application are still available only in Win32.
Fortunately, in most cases, it is not always difficult to use some of these
functions in a C# applications, as long as you observe some rules. Here is an
example:
using System;
using System.Runtime.InteropServices;

class Program
{
[DllImport("Kernel32.dll")]
public static extern bool SetConsoleTitle(string
strMessage);

static int Main()


{
SetConsoleTitle("C# Programming");

return 0;
}
}

C# 3.0 Practical Learning II 1004


A Review of Delegates
 

Introduction
The C and C++ concept of function pointer was very useful when
programming for the Microsoft Windows operating systems because the
Win32 library relies on the concept of callback functions to process messages.
For this reason and because of their functionality, callback functions were
carried out in the .NET Framework but they were defined with the name of
delegate.

A delegate is a special type of user-defined variable that is declared globally,


like a class. In fact, a delegate is created like an interface but appearing as a
method. Based on this, a delegate provides a template for a method, like an
interface provides a template for a class. Like an interface, a delegate is not
defined. Its role is to show what a useful method would look like. To support
this concept, a delegate can provide all the necessary information that would
be used on a method. This includes a return type, either no argument or one
or more arguments.

Declaring a Delegate
To declare a delegate, you use the delegate keyword. The basic formula
used to create a delegate is:
[attributes] [modifiers] delegate result-type identifier
([formal-parameters]);

The attributes factor can be a normal C# attribute.

The modifier can be one or an appropriate combination of the following


keywords: new, public, private, protected, or internal.

The delegate keyword is required.

The ReturnType can be any of the data types we have used so far. It can also
be a type void or the name of a class.

The Name must be a valid name for a method.

C# 3.0 Practical Learning II 1005


Because a delegate is some type of a template for a method, you must use
parentheses, required for every method. If this method will not take any
argument, you can leave the parentheses empty.

After declaring a delegate, remember that it only provides a template for a


method, not an actual method. In order to use it, you must define a method
that would carry an assignment the method is supposed to perform. That
method must have the same return type and the same (number of)
argument(s), if any. For example, the above declared delegate is of  type
void and it does not take any argument. After implementing the method, you
can associate it to the name of the delegate. To do that, where you want to
use the method, first declare a variable of the type of the delegate using the
new operator. In the parentheses of the constructor, pass the name of the
method. The declaration gives meaning to the delegate. To actually use the
method, call the name of the delegate as if it were a defined method.

Here is an example that uses a delegate:


using System;
using System.Windows.Forms;

delegate void dlgSimple();

class Exercise : Form


{
public Exercise()
{
dlgSimple Announce = new dlgSimple(Welcome);

Announce();

this.InitializeComponent();
}

private static void Welcome()


{

private void InitializeComponent()


{
}

static void Main()


{
Exercise form;

form = new Exercise();

Application.Run(form);
}
}

C# 3.0 Practical Learning II 1006


You can also declare a delegate that returns a value. When defining a method
that would be associated with the delegate, remember that that method must
return the same type of value. Here is an example:
using System;
using System.Windows.Forms;

delegate double Addition();

class Exercise : Form


{
public Exercise()
{
Addition Add = new Addition(Plus);

this.InitializeComponent();

TextBox txtBox = new TextBox();


Controls.Add(txtBox);

txtBox.Text = Add().ToString();
}

private static double Plus()


{
double a = 248.66, b = 50.28;

return a + b;
}

private void InitializeComponent()


{
}

static void Main()


{
Exercise form;

form = new Exercise();


Application.Run(form);
}
}

This would produce:

Delegates and Classes

C# 3.0 Practical Learning II 1007


In the above introductions, we associated delegates with only methods of the
main class. Because delegates are usually declared globally, that is outside of
a class, they can be associated with a method of any class, provided the
method has the same return type (and the same (number of) argument(s))
as the delegate. When we created the methods of the main class, we defined
them as static, since all methods of the main class must be declared static.

Methods of any class can also be associated to delegates. Here is an example


of two methods associated with a common delegate:
using System;
using System.Collections.Generic;
using System.ComponentModel;

using System.Data;

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

namespace WindowsApplication2
{
delegate double Multiplication();

public class Cube


{
private double _side;

public double Side


{
get { return _side; }

set { _side = value; }


}

public Cube()
{
_side = 0;
}

public Cube(double s)
{
_side = s;
}

public double Area()


{
return 6 * Side * Side;
}

public double Volume()


{
return Side * Side * Side;
}
}

C# 3.0 Practical Learning II 1008


public partial class Form1 : Form
{
public Form1()
{
Cube SmallBox = new Cube(25.58);

Multiplication AreaDefinition = new


Multiplication(SmallBox.Area);
Multiplication VolDefinition = new
Multiplication(SmallBox.Volume);

InitializeComponent();

txtSide.Text = SmallBox.Side.ToString();
txtArea.Text = AreaDefinition().ToString();
txtVolume.Text = VolDefinition().ToString();
}
}
}

This would produce:

Delegates Compositions
One of the characteristics that set delegates apart from C/C++ function pointers
is that one delegate can be added to another using the + operation. This is
referred to as composition. This is done by adding one delegate variable to
another as in a = b + c.

A Delegate That Takes One of More Arguments


If you want to associate a method that takes arguments to a delegate, when
declaring the delegate, provide the necessary argument(s) in its parentheses.
Here is an example of a delegate that takes two arguments (and returns a
value):
delegate double Addition(double x, double y);

When defining the associated method, besides returning the same type of
value if not void, make sure that the method takes the same number of
arguments. Here is an example:

C# 3.0 Practical Learning II 1009


using System;

delegate double Addition(double x, double y);

class Exercise
{
private static double Plus(double a, double b)
{
return a + b;
}

static int Main()


{
return 0;
}
}

Once again, to associate the method, declare a variable of the type of


delegate and pass the name of the method to the constructor of the delegate.
Here is an example:
Addition Add = new Addition(Plus);

Notice that only the name of the method is passed to the delegate. To actually
use the delegate, when calling it, in its parentheses, provide a value for the
argument(s) conform to the type specified when declaring the delegate.

A Delegate Passed as Argument


Using delegates, one method can be indirectly passed as argument to another
method. To proceed, first declare the necessary delegate. Here is a example
of such a delegate:
using System;

namespace GeometricFormulas
{
public delegate double Squared(double x);

public class Circle


{
private double _radius;

public double Radius


{
get { return _radius; }

set { _radius = value; }


}
}
}

A delegate can be passed as argument to a method. Such an argument would


be used as if it were a method itself. This means that, when accessed in the

C# 3.0 Practical Learning II 1010


body of the method, the name of the delegate must be accompanied by
parentheses and if the delegate takes an argument or argument, the
argument(s) must be provided in the parentheses of the called delegate. Here
is an example:
using System;

namespace GeometricFormulas
{
public delegate double Squared(double x);

public class Circle


{
private double _radius;

public double Radius


{
get { return _radius; }

set { _radius = value; }


}

public double Area(Squared sqd)


{
return sqd(_radius) * Math.PI;
}
}
}

After declaring a delegate, remember to define a method that implements the


needed behavior of that delegate. Here is an example:
using System;

namespace GeometricFormulas
{
public delegate double Squared(double x);

public class Circle


{
private double _radius;

public static double ValueTimesValue(double Value)


{
return Value * Value;
}
}
}

You can also define the associated method in another class, not necessarily in
the class where the delegate would be needed. Once the method that
implements the delegate is known, you can use the delegate as you see fit.
To do that, you can declare a variable of the type of that delegate and pass
the implementing method to its constructor. Here is an example:

C# 3.0 Practical Learning II 1011


using System;

namespace GeometricFormulas
{
public delegate double Squared(double x);

public class Circle


{
private double _radius;

public static double ValueTimesValue(double Value)


{
return Value * Value;
}

public double Area(Squared sqd)


{
return sqd(_radius) * Math.PI;
}

public void CircleCharacteristics()


{
Squared Sq = new Squared(ValueTimesValue);
}
}

This declaration gives life to the delegate and can then be used as we have
proceed with delegates so far.

Application Online Help


 

Introduction
Providing help is one of the most neglected areas of application development. There are
various reasons to this. Some programmers tend to think that help is such a small job
that it should be left to non-programmers. This is not a valid argument since the person
who creates an application knows it better than anybody. Asking someone else to create
help for your application would only slow the process because the other person would
need to have new and more information about the application. Another reason is that,
most programmers who want to take care of programming when creating an application
think that they are working double to create a single program. This drives them to set this

C# 3.0 Practical Learning II 1012


aspect aside and continue only with the application, thinking that they can come back to
take care of help when the application is complete. What makes this unrealistic is that,
sometimes when they finish the application, they are "tired".

There are various small but effective techniques you can use to provide help in your application: ne

Practical Learning: Introducing Help


1. Start Microsoft Visual C#

2. Create a Windows Application named ClarksvilleIceCream1

3. In the Properties window, change the form's Text to Clarksville Ice Cream

4. Design the form as follows:


 

Control Name Text Additional Properties

GroupBox grpIceCream    

Label   Order Date:  

DateTimePicker dtpOrderDate   Format: Short

Label   Order Time:  

DateTimePicker dtpOrderTime   Format: Time

C# 3.0 Practical Learning II 1013


ShowUpDown: True

Label   Flavor:  

ComboBox cboFlavors    

Label   Container:  

ComboBox cboContainers    

Label   Ingredient:  

ComboBox cboIngredients    

Label   Scoops:  

TextBox txtScoops 1 TextAlign: Right

Label   Order Total:  

TextBox txtOrderTotal 0.00 TextAlign: Right

Button btnNewOrder New Order  

Button btnCalcTotal Calculate Total  

Button btnClose Close  

5. Click the combo box to the right of the Flavor label. Then, in the Properties, click the ellips
property and create the list with:
 

Vanilla
Cream of Cocoa
Chocolate Chip
Cherry Coke

C# 3.0 Practical Learning II 1014


Butter Pecan
Chocolate Cookie
Chunky Butter
Organic Strawberry
Chocolate Brownies
Caramel Au Lait

6. Click OK

7. Click the combo box to the right of the Container label. Then, in the Properties, click the e
Items property and create the list with:
 

Cone
Cup
Bowl

8. Click OK

9. Click the combo box to the right of the Ingredient label. Then, in the Properties, click the e
Items property and create the list with:
 

None
Peanuts
Mixed Nuts
M&M
Cookies

10. Click OK

11. Double-click the New Order button to access its Click event and implement it as follows:
 
private void btnNewOrder_Click(object sender, EventArgs e)
{
// If the user clicks New Order, we reset the form
with the default values
this.dtpOrderDate.Value = DateTime.Today;
this.dtpOrderTime.Value = DateTime.Now;
this.cboFlavors.Text = "Vanilla";
this.cboContainers.Text = "Cone";
this.cboIngredients.Text = "None";
this.txtScoops.Text = "1";
this.txtOrderTotal.Text = "0.00";
}

12. Return to the form

C# 3.0 Practical Learning II 1015


13. Double-click the Calculate Total button to access its Click event

14. Implement it as follows:


 
private void btnCalcTotal_Click(object sender, EventArgs e)
{
double PriceContainer = 0.00,
PriceIngredient = 0.00,
PriceScoops = 0.00,
OrderTotal = 0.00;
int NumberOfScoops = 1;

// Find out what container the customer requested


// The price of a container depends on which one the
customer selected
if( cboContainers.Text == "Cone" )
PriceContainer = 0.55;
else if( cboContainers.Text == "Cup" )
PriceContainer = 0.75;
else
PriceContainer = 1.15;

// If the customer selected an ingredient, which is not


"None", add $.95
if( cboIngredients.Text != "None" )
PriceIngredient = 0.95;

try {
// Get the number of scoops
NumberOfScoops = int.Parse(this.txtScoops.Text);

if( NumberOfScoops == 2 )
PriceScoops = 2.55;
else if( NumberOfScoops == 3 )
PriceScoops = 3.25;
else
PriceScoops = 1.85;
}
catch(FormatException)
{
MessageBox.Show("The value you entered for the scoops
is not valid" +
"\nOnly natural numbers such as
1, 2, or 3 are allowed" +
"\nPlease try again");
}

// Make sure the user selected a flavor,


// otherwise, there is no reason to process an order
if( cboFlavors.Text != "" )
OrderTotal = PriceScoops + PriceContainer +
PriceIngredient;

this.txtOrderTotal.Text = OrderTotal.ToString();

C# 3.0 Practical Learning II 1016


}

15. Return to the form

16. Double-click the Close button and implement its Click event as follows:
 
private void btnClose_Click(object sender, EventArgs e)
{
Close();
}

17. Test the application. Here is an example:


 

18. Close the form and return to Visual Studio

Status Bar Messages


One way you can provide simple help consists of displaying short indicative messages on a status b
first create sections, called panels, on a status bar and then display the necessary messages in the
The message can be anything but it should consist of just a few words to fit in its section without go

Practical Learning: Helping Through a Status Bar


1. Display the from and expand its bottom border a little bit

2. On the Toolbox, click StatusStrip and click the bottom section of the form

3. In the Properties window, click Items and click its ellipsis button

4. In the Select Item and Add to List Below combo box, select StatusLabel if necessa
On the right side, set the Text to Ready
 

C# 3.0 Practical Learning II 1017


5. Click OK
 

6. On the form, click the dtpOrderDate control; that is, the combo box on the right side of th

7. In the Properties window, click the Events button and double-click MouseMove

8. Return to the form

9. In the same way, initiate the MouseMove event of the dtpOrderTime date time picker, the
box, the cboContainers combo box, the cboIngredients combo box, the txtScoops text box

C# 3.0 Practical Learning II 1018


text box, and the form

10. Implement the events as follows:


 
private void dtpOrderDate_MouseMove(object sender, MouseEventArgs e)
{
statusStrip1.Items[0].Text =
"Specify the date this order was processed";
}

private void dtpOrderTime_MouseMove(object sender, MouseEventArgs e)


{
statusStrip1.Items[0].Text =
"Specify the time this order was processed";
}

private void cboFlavors_MouseMove(object sender, MouseEventArgs e)


{
statusStrip1.Items[0].Text = "Select the customer's desired
flavor";
}

private void cboContainers_MouseMove(object sender, MouseEventArgs


e)
{
statusStrip1.Items[0].Text =
"Select the type of object that will contain the ice cream";
}

private void cboIngredients_MouseMove(object sender, MouseEventArgs


e)
{
statusStrip1.Items[0].Text =
"Select an ingredient to spice the ice cream";
}

private void txtScoops_MouseMove(object sender, MouseEventArgs e)


{
statusStrip1.Items[0].Text =
"Select the number of scoops to fill the container";
}

private void txtOrderTotal_MouseMove(object sender, MouseEventArgs


e)
{
statusStrip1.Items[0].Text =
"This displays the total of the order";
}

11. Return to the form and click a border of the group box

12. In the Events section of the Properties, generate the event of the MouseHover field, and implement
 

C# 3.0 Practical Learning II 1019


private void grpIceCream_MouseHover(object sender, EventArgs e)
{
this.statusStrip1.Items[0].Text = "Ready";
}

13. Return to the form and click an area of its body away from any control on it

14. In the Events section of the Properties, generate the event of the Move field, and implement it as fo
 
private void grpIceCream_MouseHover(object sender, EventArgs e)
{
this.statusStrip1.Items[0].Text = "Ready";
}

15. Test the application


 

16. After using it, close the form and return to Visual Studio

Tool Tips
A tool tip is a small yellow box that displays a word or a group of words when the user positio
of a control:

To create a tool tip system in a Visual Studio 2005 application, first add a ToolTip control to a
ToolTip control, the form and all controls on it receive a new field in the Properties window

C# 3.0 Practical Learning II 1020


control is called ToolTip1, the new field in the Properties window for each control is ToolTip on
a tool tip for a control, first click it on the form. Then, in the Properties window, click ToolTip
the desired tool tip.

Practical Learning: Adding Tool Tips

1. To prepare for tool tips, on the Toolbox, click ToolTip and click the form

2. On the form, click each control and, in the Properties window, set its ToolTip On ToolTip property
 

Control ToolTip On ToolTip1

dtpOrderDate Click the arrow to select a date

Click each section, then click one of the arrows to change its
dtpOrderTime
value

cboFlavors Click the arrow to display a list, then select a flavor from the list

cboContainers Click to display the list of containers and select one

cboIngedients Display the list of ingredients and make the customer's choice

txtScoops Enter the number of scoops (1, 2, or 3) to fill the container

txtOrderTotal This displays the total amount of this order

btnNewOrder Click here to reset the form

btnCalcTotal Click here to calculate the total of the order

btnClose Click here to Close the form

3. Test the application


 

C# 3.0 Practical Learning II 1021


4. Close it and return to Visual Studio

Online Help
 

Introduction
Online help is the system of providing help files with an application. Online help is
usually available from the main menu through a menu group created under a Help
category.

In the past, the techniques to provide or program online help were not always easy. The
early implementations of help were created in a system called WinHelp. This required
using a Rich Text Format (rtf) file and appropriately formatting it. It is possible that,
when folks at Microsoft developed WinHelp, they had only Microsoft Word in mind. It
was difficult to get the required file ready if you were using another application such as
WordPad or WordPerfect...

Creating the help file was not enough. Once the file was ready, it had to be added to
application, and appropriately. This back and forth gymnastic was a great motivation for neg
As if these difficulties were not enough, or because of these difficulties, Microsoft created ano
system called HTML Help. This neither solved most problems nor created an easier solution
this time, this HTML Help is widely used and many companies, such as AutoDesk (AutoCAD)
Macromedia to name just two, have adopted it . Many companies such as Borland, Jasc, jus

C# 3.0 Practical Learning II 1022


name two, are still using WinHelp. This indicates that HTML Help didn't solve all problems and
not anonymously adopted.
Because HTML Help is the most supported help system by Microsoft, we will use it. Also, it is easie
use HTML Help in a Microsoft Visual Studio 2005 application than to use WinHelp.

Practical Learning: Introducing Online Help


1. To create a new form, on the main menu, click Project -> Add Windows Form...

2. In the Add New Item dialog box, set the name of the form to Calculation, and click Add

3. Design the new form as follows:


 

Control Name Text Additional Properties

Label   Order Total:  

TextAlign: Right
TextBox txtOrderTotal 0.00
Modifier: Public

Amount
Label    
Tended:

TextBox txtAmountTended 0.00 TextAlign: Right

Button btnCalculate Calculate  

Label   Difference:  

TextBox txtDifference 0.00 TextAlign: Right

C# 3.0 Practical Learning II 1023


Button btnClose Close  

4. Double-click both buttons and implement their Click events as follows:


 
private void btnCalculate_Click(object sender, EventArgs e)
{
double TotalOrder,
AmountTended = 0.00,
Difference;

// Get the value of the total order. Actually, this value


// will be provided by the main form
TotalOrder = double.Parse(this.txtOrderTotal.Text);

try
{
// The amount tended will be entered by the user
AmountTended =
double.Parse(this.txtAmountTended.Text);
}
catch(FormatException)
{
MessageBox.Show("The amount you entered is not " +
"valid - Please try again!");
}

// Calculate the difference of both values, assuming


// that the amount tended is higher
Difference = AmountTended - TotalOrder;

// Display the result in the Difference text box


this.txtDifference.Text = Difference.ToString();
}

private void btnClose_Click(object sender, EventArgs e)


{
Close();
}

5. Display the first form (Form1.cs [Design])

6. Add a new button to the bottom side of the form between the other buttons

7. Change its values in the Properties window as follows:


Name:    btnDifference
Text:     Difference
Enabled: False
ToolTip on ToolTip1: Click to calculate the amount owed to the customer

8. Double-click the Difference button and implement its Click event as follows:
 

C# 3.0 Practical Learning II 1024


private void btnDifference_Click(object sender, EventArgs
e)
{
// Declare a variable for the Calculation form
Calculation dlgCalculation = new Calculation();

// Transfer the current value of the Order Total text


// box from the main form to the other form
dlgCalculation.txtOrderTotal.Text =
this.txtOrderTotal.Text;
// Display the other form
dlgCalculation.ShowDialog();
}

9. Change the Click events of the Calculate Total  and the New Order buttons as follows:
 
private void btnNewOrder_Click(object sender, EventArgs e)
{
// If the user clicks New Order, we reset
// the form with the default values
this.dtpOrderDate.Value = DateTime.Today;
this.dtpOrderTime.Value = DateTime.Now;
this.cboFlavors.Text = "Vanilla";
this.cboContainers.Text = "Cone";
this.cboIngredients.Text = "None";
this.txtScoops.Text = "1";
this.txtOrderTotal.Text = "0.00";
this.btnDifference.Enabled = false;
}

private void btnCalcTotal_Click(object sender, EventArgs e)


{
double PriceContainer = 0.00,
PriceIngredient = 0.00,
PriceScoops = 0.00,
OrderTotal = 0.00;
int NumberOfScoops = 1;

// Find out what container the customer requested


// The price of a container depends on which
// one the customer selected
if (cboContainers.Text == "Cone")
PriceContainer = 0.55;
else if (cboContainers.Text == "Cup")
PriceContainer = 0.75;
else
PriceContainer = 1.15;

// If the customer selected an ingredient,


// which is not "None", add $.95
if (cboIngredients.Text != "None")
PriceIngredient = 0.95;

try

C# 3.0 Practical Learning II 1025


{
// Get the number of scoops
NumberOfScoops = int.Parse(this.txtScoops.Text);

if (NumberOfScoops == 2)
PriceScoops = 2.55;
else if (NumberOfScoops == 3)
PriceScoops = 3.25;
else
PriceScoops = 1.85;
}
catch (FormatException)
{
MessageBox.Show("The value you entered for the scoops is not
valid" +
"\nOnly natural numbers such as 1, 2, or 3 are
allowed" +
"\nPlease try again");
}

// Make sure the user selected a flavor,


// otherwise, there is no reason to process an order
if (cboFlavors.Text != "")
OrderTotal = PriceScoops + PriceContainer + PriceIngredient;

this.txtOrderTotal.Text = OrderTotal.ToString();
this.btnDifference.Enabled = true;
}

10. Test the application. Here is an example:


 

C# 3.0 Practical Learning II 1026


11. After using it, close it and return to Visual Studio

The Help Provider


Context-sensitive help allows the user to get local help on a particular control. This works by
user who can first click a control and then press Shift+F1. This displays a yellow box with a w
or a group of words:

This help is easier to provide in a dialog box because a dialog has a feature not available o
form. It consists of adding a button with a question mark and then creating the words that w
display eventually. When you create this type of dialog box, the user can click the question ma
button and click a control. The user can also press Shift+F1. This causes the mouse pointer t
equipped with a question mark. The user can then click a control and a yellow box would ap
for that control, providing help.

C# 3.0 Practical Learning II 1027


To make it easy to provide online help in a Visual Studio 2005application, the .NET Framew
provides the HelpProvider control. After adding this control to the application, the form an
controls on it receive a new property labeled HelpString On HelpProvider1 . You can then type
desired string in the field of the Properties window for each control that would display context-sens
help.

Practical Learning: Using Context-Sensitive Help


1. Display the Calculation form and click an area to select the form

2. Change the following values of the form in the Properties window:


FormBorderStyle: FixedDialog
HelpButton: True
MaximizeBox: False
MinimizeBox: False
ShowInTaskbar: False

3. In the Components section of the Toolbox, click HelpProvider and click the form
 

4. Using the Properties window, change the following values for the indicated controls:
 

C# 3.0 Practical Learning II 1028


Control HelpString On HelpProvider1

txtOrderTotal This is the total amount of the current order

txtAmountTended This is the amount the customer tended

Click here to calculate the difference between the amount tended


btnCalculate
and the total price of the order

This displays the difference between the amount tended and the
txtDifference
total of the order

btnClose Click here to close the dialog box

5. Execute the application

6. When it displays, process an order and click the Calculate Difference button

7. In the Calculation dialog box, click the question mark button in the title bar and click on the text bo
or buttons
 

8. After using the application, close the forms and return to Visual Studio

9. Display the main form (Form1.cs [Design])

10. To add a menu to the application, on the Toolbox, click MenuStrip and click the form

11. On the form, click Type Here. Type &File and press the down arrow key

12. Type E&xit and press Enter

13. On the right side of File (on the form), click Type Here

14. Type &Help and press the down arrow key

C# 3.0 Practical Learning II 1029


15. Type &Contents... and press the down arrow key

16. Type &Index... and press the down arrow key

17. Type &Search... and press Enter


 

18. On the form, click File and double-click Exit

19. Implement its event as follows:


 
private void exitToolStripMenuItem_Click(object sender,
EventArgs e)
{
Close();
}

20. Test the application then close it and return to Visual Studio

Introduction to HTML Help


The online help we described above provides only small yellow boxes. It is called context-sens
because it provides its assistance on only a control of the form. Another technique, in fact hi
supported with any commercial program, consists of providing an external application
resembles a book. This allows the user to get more detailed information about almost any as
of the application.

To provide online help in a Visual Studio 2005 application, you can use an external system.
consists of creating a complete application whose only purpose is to describe another applica

C# 3.0 Practical Learning II 1030


This means that, in the beginning, both applications are not related in any way. With HTML H
you must first create HTML files. You create these files anyway you like but, in this case, they
meant to provide support for a specific application. Therefore, when creating the files, try to di
them by issues. For example, you can create a file for each form of your application and use
file to describe what the form or dialog box is used for. You still can use any approach to cr
the files you would need. Experience will guide you eventually into knowing what to put in th
files.
After creating the HTML files, you can open HTML Help Workshop which is a complete but sepa
application. This application is freely available from Microsoft and you can download it from the M
web site.

Practical Learning: Creating an HTML Help File


1. Using Windows Explorer or My Computer, create a folder named cic

2. Inside of the cic folder, create a folder named images

3. Save the following pictures in the cic\images folder:


 

C# 3.0 Practical Learning II 1031


4. Start Notepad and create a Cascading Style Sheet file to format the body tag and the main
title of the pages. Here is an example:
 
body
{
font-size: 10pt;

C# 3.0 Practical Learning II 1032


color: black;
margin-top: 0pt;
margin-left: 0pt;
font-family: Verdana, Tahoma, Arial, Sans-Serif;
}

.maintitle
{
font-weight: bold;
font-size: 24pt;
color: blue;
font-family: Garamond, Georgia, 'Times New Roman' ,
Serif;
}

5. Save the file as cic.css in the cic folder

6. Start another file with the following contents


 
<html>

<head>

<link rel="stylesheet" type="text/css" href="cic.css">

<title>Overview of Clarksville Ice Cream</title>


</head>

<body>

<table border="0" width="100%" cellspacing="0" cellpadding="0">


<tr>
<td width="100%" align="center">
<p class="maintitle">Overview of Clarksville Ice
Cream</p></td>
</tr>
<tr>
<td width="100%" bgcolor="#0000FF" height="2"></td>
</tr>
</table>

<p>&nbsp;</p>
<center><img border="0" src="images/main1.gif"
alt="The main window of the application"
width="416" height="284"></center>
<p>Clarksville Ice Cream is a computer application used to
process customers
orders. It allows an employee to receive requests from a
customer, based on what
is available in the menu. When the order is complete, an ice
cream is
&quot;prepared&quot; and handed to the customer. As a
commercial business, the
application calculates the total amount. The amount is read to

C# 3.0 Practical Learning II 1033


the customer who
hands money to the clerk to complete the transaction</p>

</body>

</html>

7. Save it as introduction.htm

8. Start another file with the following contents


 
<html>

<head>

<link rel="stylesheet" type="text/css" href="cic.css">

<title>Customer Order Form</title>


</head>

<body>

<table border="0" width="100%" cellspacing="0" cellpadding="0">


<tr>
<td width="100%" align="center">
<p class="maintitle">Customer Order Form</p>
</td>
</tr>
<tr>
<td width="100%" bgcolor="#0000FF" height="2"></td>
</tr>
</table>

<p>&nbsp;</p>
<p>The main or opening window of this application displays a
form used to
process customers orders. The top section of the form, also
called the title
bar, is equipped with a menu called the main menu. this menu
allows the user to
start a new order or to close the application. To use this main
menu, you can
click one of the top-level words such as File. This causes the
menu category of
your choice to expand:</p>
<center>
<img border="0" src="images/main2.gif"
alt="The main menu" width="416" height="284"></center>
<p>After using a menu item, you can click it or click somewhere
else to collapse
it.</p>

<p>The other objects on the main form allow the user to process
an order by

C# 3.0 Practical Learning II 1034


selecting items from the Windows controls. Once an order is
ready, the user can
click the Calculate Total button. This evaluates the total
price of the order
and displays it in the text box on the right side of Order
Total.</p>

<p>To start a new customer order, the user can click the New
Order button. This
resets all controls on the form:</p>

<center>
<img border="0" src="images/main3.gif"
alt="Customer Form Reset" width="416"
height="284"></center>

<p>When an order has been calculated, the user can click the
Calculate
Difference button to evaluate the diffence.</p>

</body>

</html>

9. Save it as mainform.htm

10. Start another file with the following contents


 
<html>

<head>

<link rel="stylesheet" type="text/css" href="cic.css">

<title>Difference Calculation</title>
</head>

<body>

<table border="0" width="100%" cellspacing="0" cellpadding="0">


<tr>
<td width="100%" align="center">
<p class="maintitle">Difference Calculation</p>
</td>
</tr>
<tr>
<td width="100%" bgcolor="#0000FF" height="2"></td>
</tr>
</table>

<p>&nbsp;</p>
<p>The Calculation dialog box allows a user to easily calculate
the amount of
money owed to a customer. After a customer has placed an order

C# 3.0 Practical Learning II 1035


and given money
to the clerk, the user can display this dialog box. When it
comes up, the top
text box of this window already displays the amount of the
customer's order. The
user can then simply enter the amount the customer gave in the
Amount Tended
text box. Then the user can click Calculate</p>
<center>
<img border="0" src="images/calculation1.gif"
width="304" height="152"></center>
<p>When the user has clicked the Calculate button, it
calculates the difference
and displays it in the Difference text box. After using this
dialog box, the
user can close it by clicking Close.</p>
<p>&nbsp;</p>

</body>

</html>

11. Save it as calculation.htm

12. Start another file with the following contents


 
<html>

<head>

<title>Clarksville Ice Cream - Home</title></head>

<body>
<h1>Clarksville Ice Cream</h1>
<p><a href="introduction.htm">Introduction</a></p>
<p><a href="mainform.htm">The Main Form</a></p>
<p><a href="calculation.htm">The Difference Calculation Dialog
Box</a></p>
</body>

</html>

13. Save it as index.htm

14. Start HTML Help Workshop

15. On the main menu of HTML Help Workshop, click File -> New
 

C# 3.0 Practical Learning II 1036


16. In the New dialog box, make sure Project is selected and click OK
 

17. In the first page of the New Project wizard, click Next
 

C# 3.0 Practical Learning II 1037


18. In the second page of the wizard, click Browse

19. Locate the cic folder you created and display it in the Save In combo box

20. Set the File Name to cicoh


 

21. Click Open


 

C# 3.0 Practical Learning II 1038


22. In the second page, click Next
 

23. In the third page, read the text. Click the HTML files (.htm) check box and click Next

24. In the fourth page, click Add

25. In the Open dialog box, press and hold Ctrl. Then click each htm file to select them all
 

C# 3.0 Practical Learning II 1039


26. Click Open
 

27. In the fourth page, click Next

28. In the last page of the wizard, click Finish

29. In HTML Help Workshop, click the Contents tab


In the dialog box that displays, make sure the first radio button is selected

C# 3.0 Practical Learning II 1040


 

30. Click OK

31. In the Save As dialog box, accept the suggested name


 

C# 3.0 Practical Learning II 1041


32. Click Save

33. Click the Insert a Heading button

34. In the Table Of Contents Entry dialog box, in the Entry Title text box, type Clarksville
Cream and click Add

35. In the Path Or URL dialog box, select the Clarksville Ice Cream - Home and click OK
 

36. Click OK

37. Click the Insert A Page button

38. In the message box that displays, click No

39. In the Entry Title text box, type Introduction and click Add

40. In the Path Or URL dialog box, select the Overview of Clarksville Ice Cream and click OK
 

C# 3.0 Practical Learning II 1042


41. In the Table Of Contents Entry dialog box, click OK

42. In the same way, create new pages under the Introduction heading using the following table
 

New Page Title Page or URL

Customer Order
Customer Order Form
Form

Difference
Difference Calculation
Calculation

43. In HTML Help Workshop, click the Index tab. In the dialog box that comes up, make sure
top radio button is selected
 

C# 3.0 Practical Learning II 1043


44. Click OK

45. Accept the suggested name of the file and press Enter

46. Click Insert A Keyword

47. In the Keyword text box, type Calculation and click Add

48. In the Path Or URL dialog box, click Difference Calculation and click OK twice

49. In the same way, create new keywords using the following table (sometimes you may receive a
message box asking whether you want to create the keyword above the other; it doesn't matter, for t
exercise, whether you click Yes or No):
 

New Keyword Page or URL

amount Difference Calculation

money Difference Calculation

customer Difference Calculation

order Difference Calculation

C# 3.0 Practical Learning II 1044


clerk Difference Calculation

window Difference Calculation

Amount
Difference Calculation
Tended

Calculate Difference Calculation

Close Difference Calculation

computer Overview of Clarksville Ice Cream

Application Overview of Clarksville Ice Cream

employee Overview of Clarksville Ice Cream

menu Overview of Clarksville Ice Cream

commercial Overview of Clarksville Ice Cream

business Overview of Clarksville Ice Cream

transaction Overview of Clarksville Ice Cream

Main Menu Customer Order Form

category Customer Order Form

choice Customer Order Form

50. Click the Sort Keywords Alphabetically button


 

C# 3.0 Practical Learning II 1045


51. Click the Project tab

52. Click the Add/Modify Window Definitions button

53. Set the name to MainWnd and press Enter

54. Set the Title Bar Text to Clarksville Ice Cream

55. Click the Buttons tab then click the Home and the Locate check boxes

C# 3.0 Practical Learning II 1046


56. Click the Position tab

57. Set the Width to 800 and the Height to 600


 

C# 3.0 Practical Learning II 1047


58. Click the Files tab

59. Set the Default and the Home choices to index.htm


 

C# 3.0 Practical Learning II 1048


60. Click the Navigation Pane tab

61. Click the Search Tab and the Advanced check boxes
 

C# 3.0 Practical Learning II 1049


62. Click OK
 

63. When the Resolve Window Definition wizard comes up, in the first page, make sure the
window defined previously is selected in the Window Type combo box and click Next

64. Click the Compile Full-Text Information check box


 

C# 3.0 Practical Learning II 1050


65. Click Next

66. In the second page, accept the defaults and click Next

67. In the third page, accept the default and click Finish

68. To create the help file, click the Save All Files And Compile button
 

C# 3.0 Practical Learning II 1051


69. While the compilation is over, close the HTML Help Workshop window

HTML Help and Visual Studio 2005Applications


After creating the HTML Help application, you can use a HelpProvider control to connect
your application. The HelpProvider control is equipped wit the HelpNamespace provider.
property allows you to specify the application that contains the help application. Besides
HelpNamespace property, the HelpProvider control provides various methods to manage help

HTML Help can be provided to a Visual Studio 2005 application through the Help class.
overloaded ShowHelp() method is used to specify the help file to display and possibly additi
information. Notice that all versions take a first argument as a Control type. This is the pa
control from where the online help will be provided.

The first version allows you specify the help file. It can be the help file specified in
HelpProvider.HelpNamespace property mentioned above.

The second and the fourth versions allow you to specify the tab of the HTML Help window
display when the method is called. This is done through the HelpNavigator enumerator that
a value for each tab of the HTML Help window. the fourth version can be used to open the H
Help window from its Find tab and specify a keyword to search for.

C# 3.0 Practical Learning II 1052


The third version can be used to open a help file based on a keyword.

The ShowHelpIndex() method can be used to open the Index tab of the HTML Help window.

Practical Learning: Providing Online Help to an Application


1. Open Windows Explorer or My Computer

2. In the cic folder, copy the cicoh.chm file to the clipboard and paste it in the folder of the
current project (ClarckvilleIceCream1)

3. Display the main form

4. In the Components section of the Toolbox, click HelpProvider and click the form

5. In the Properties window, change its Name to hpvIceCream and click HelpNamespace

6. Click the ellipsis button of the HelpNamespace property

7. From the CIC1 folder of the current project, select the cicoh.chm file
 

8. Click Open

9. On the main menu of the form, click Help and double-click Contents

10. Implement the event as follows:

C# 3.0 Practical Learning II 1053


 
private void contentsToolStripMenuItem_Click(object sender,
EventArgs e)
{
Help.ShowHelp(this, hpvIceCream.HelpNamespace);
}

11. Display the main form. On the main menu of the form, double-click Index

12. Implement the event as follows:


 
private void indexToolStripMenuItem_Click(object sender,
EventArgs e)
{
Help.ShowHelpIndex(this, hpvIceCream.HelpNamespace);
}

13. Display the main form. On the main menu of the form, double-click Search

14. Implement the event as follows:


 
private void searchToolStripMenuItem_Click(object sender,
EventArgs e)
{
Help.ShowHelp(this, hpvIceCream.HelpNamespace,
HelpNavigator.Find, "");
}

15. Test the application. When it displays, click the Help menu of the form and click one of the
menu items
 

C# 3.0 Practical Learning II 1054


16. After using it, close the online help window, close the form, and return to Visual Studio

The Toolbox
 

Introduction
A Windows control is a graphical object that allows the user to interact with the

C# 3.0 Practical Learning II 1055


computer. The controls are as varied as the needs and goals are. Because there are so
many controls for various purposes, their insertion to an application and their
configuration are left to the computer programmer. The Toolbox is the accessory that
provides most of the controls used in an application:

By default, the Toolbox is positioned on the left side of the IDE. To change
that position, you can drag its title bar away and dock it to another side of the
IDE. The Toolbox also uses a default width to show the items on it. If the
width is too narrow or too wide, you can change it. To do this, position the
mouse to its right border and drag left or right.

The Toolbox and Additional Controls


When Microsoft Visual Studio is set up, it installs in the Toolbox the most
regularly used controls. If you are working in an environment that creates
only a particular group of applications and there are controls you hardly use,
if you want, you can remove them from the list. To remove a control, right-
click it and click Delete.

Besides the objects in the Common Controls section, other controls are left
out but are still available. Some of the left out controls were created with
the .NET Framework but are not installed by default because they are judged
hardly used. To add one or more of these left out controls, right-click
anywhere in the Toolbox and click Choose Items... In the Choose Toolbox
Items dialog box, click the .NET Framework Components tab, then click the
check box of the desired control before clicking OK:

C# 3.0 Practical Learning II 1056


In addition to custom .NET controls, some other objects called ActiveX
controls were used in previous versions of Visual Basic or Visual Studio and
are available. To take care of compatibility issues, most previous ActiveX
controls were reconfigured and adapted to be used in a .NET application. To
add some of these left out controls, right-click anywhere in the Toolbox and
click Choose Items... In the Choose Toolbox Items dialog box, click the COM
Components tab, select the desired control before clicking OK

C# 3.0 Practical Learning II 1057


The Sections of the Toolbox
When you start a Windows Forms Application, it provides various controls on
the Toolbox so you can choose which ones are appropriate for your particular
application. Controls can be set by categories based on their function or role.
A container is a control whose main purpose is to host other controls. To
design it, you pick up objects from the Toolbox and drop them where desired.
The Toolbox organizes its items in categories and each category is
represented by a button:

If the available list of categories is not enough, you can add a new section of
your choice. By default, Visual Studio hides some categories because they are

C# 3.0 Practical Learning II 1058


judged hardly used. To display these additional sections, you can right-click
anywhere in the Toolbox and click Show All:

If you still want an additional tab not included in the list, you can add one (or
more). To do that, right-click anywhere in the Toolbox and click Add Tab. You
would be prompted to provide a name. After typing the new name, press
Enter.

The Layout of a Category


To use an object of a particular category, you can first click its button. After
selecting a category, it displays its items. In each category, a particular
button called Pointer is selected by default. This simply indicates that no item
in the group is currently selected.

By default, the items in each category are organized as horizontal wide


buttons:

C# 3.0 Practical Learning II 1059


Alternatively, you can list the items of a category as buttons of a list view. To
do that, you can right-click anywhere in the category and click List View to
remove its check box:

C# 3.0 Practical Learning II 1060


Arrangement of Items in the Toolbox
When Microsoft Visual Studio is installed, it adds the buttons in a somewhat
random order. In the beginning, this can make it difficult to find a particular
control when you need it. If you find it more convenient, you can arrange the
list of controls in any order of your choice. You have two main options. To
change the position of an item in the list, right-click it and click either Move
Up or Move Down. Alternatively, you can arrange the items in alphabetic
order. To do that, right-click anywhere in the Windows Forms section and
click Sort Items Alphabetically:

Once you have rearranged items alphabetically, the Toolbox forgets the
previous arrangement and you cannot restore it. Alternatively, you can right-
click the button of a control and click either Move Up or Move Down.

Introduction to
Application Design
 

C# 3.0 Practical Learning II 1061


Visual Control Addition

Introduction
To add a control to your application, you can select it from the Toolbox and
click the desired area on the form. Once added, the control is positioned where
your mouse landed. In the same way, you can add other controls as you judge
them necessary for your application. Here is an example of a few controls
added to a form:

Alternatively, to add a control, you can also double-click it from the Toolbox
and it would be added to the top-left section of the form.

If you want to add a certain control many times, before selecting it on the
Toolbox, press and hold Ctrl. Then click it in the Toolbox. This permanently
selects the control. Every time you click the form, the control would be added.
Once you have added the desired number of this control, on the Toolbox,
click the Pointer button to dismiss the control.

Practical Learning: Using the Toolbox

1. Start Microsoft Visual C#

2. To create a new application, on the main menu, click File -> New
Project...

3. In the Templates list, click Windows Application

4. Set the Name to DesignPractice1 and click OK

C# 3.0 Practical Learning II 1062


5. On the main menu, click View -> Toolbox.
Position the mouse on the Toolbox word and wait for the Toolbox to
expand

6. Click the Label button and position the mouse on the form
 

7. Click the form

8. Click the middle of the form to select it (the form)

9. To add another control, position the mouse again on the Toolbox word
until the Toolbox has expanded

10. Find and double-click the TextBox button

11. To use a hidden area of the form, position the mouse on the Toolbox
word. When the Toolbox has expanded, click the Auto Hide button

12. On the Toolbox, click the TreeView button and click the left section
of the form

13. After using the Toolbox, to hide it, click the Auto Hide button

14. To execute the application, on the main menu, click Debug -> Start
Without Debugging

15. After using it, close the form and return to your programming
environment

C# 3.0 Practical Learning II 1063


Copying a Control
We mentioned earlier how you could add a control many times. An alternative
is to copy a control. To do this, on the form:

 Right-click the control and click Copy. Right-click another area of the
form and click Paste

 Click (once) the control you want to copy


 

Press and hold Ctrl. Then drag the selected control to another area of
the form. The mouse cursor would display a + plus indicating that the
control is being duplicated:
 

Once you get to another area of the form, release the mouse and Ctrl

You can use these two techniques to copy a group of controls.

Dynamic Control
Creation
 

Introduction

C# 3.0 Practical Learning II 1064


The objects used in a Windows application are defined in various
assemblies. To add one of these controls to your application, you must first
know the name of its class. With this information, you can declare a variable
of its class. For example, a command button is an object of type Button that
is based on the Button class. The Button class is defined in the
System.Windows.Forms namespace of the System.Windows.Forms.dll
assembly. Based on this, to create a button, you can create a variable of type
Button. Here is an example:

using System;
using System.Windows.Forms;

public class Exercise : Form


{
private Button btnSubmit;

public Exercise()
{
}

}
public class Program
{
public static int Main()
{
Application.Run(new Exercise());
return 0;
}
}

After declaring the variable, you can use the new operator to allocate memory
for it:
public class Exercise : Form
{
private Button btnSubmit;

public Exercise()
{
btnSubmit = new Button();
}
}

This is also referred to as dynamically creating a control. After declaring the


variable and allocating memory for it, the control is available but doesn't have
a host, which makes it invisible. A control must be positioned on a host like a
form. The Form class itself contains a member variable named Controls.
This member holds a list of the objects that are placed on the form. To
specify that a control you have instantiated must be positioned on a form, the
Controls member has a method named Add. Therefore, to make an object
part of the form, pass its variable to the Add() method. Here is an example:
using System;

C# 3.0 Practical Learning II 1065


using System.Windows.Forms;

public class Exercise : Form


{
private Button btnSubmit;

public Exercise()
{
btnSubmit = new Button();
Controls.Add(btnSubmit);
}
}

public class Program


{
public static int Main()
{
Application.Run(new Exercise());
return 0;
}
}

This makes it possible for  the control to appear on the form when the form
displays to the user:

These two techniques of visual addition of objects and dynamic creation are
the most used to add Windows controls to an application. The Windows
controls are also called components.

Initializing the Components


Because there can be many controls used in a program, instead of using the
constructor to initialize them, the Visual Studio standards recommend that
you create a method called InitializeComponent to initialize the various

C# 3.0 Practical Learning II 1066


objects used in your application. Then simply call that method from the
constructor of your form. This would be done as follows:
using System;
using System.Windows.Forms;

public class Exercise : Form


{
private Button btnSubmit;

private void InitializeComponent()


{
btnSubmit = new Button();
Controls.Add(btnSubmit);
}

public Exercise()
{
InitializeComponent();
}
}

public class Program


{
public static int Main()
{
Application.Run(new Exercise());
return 0;
}
}

Notice that the control is created in the InitializeComponent() method.

Using a Partial Class


Starting in Microsoft Visual C# 2005, and probably getting close to C++, you
can use two files to create and use a form. Each file would hold a partial
definition of the class. As done in a header file of a C++ application, the first
file in C# would hold the variable  or control declarations. While in C++ a
header file holds the same name (but different extensions) as its
corresponding source file, because C# does not have the concepts of header
and source file, in C#, each file must have a different name. Here is a starting
file:
using System;
using System.Windows.Forms;

public partial class Exercise


{
private Button btnSubmit;
}

Like the source file of a C++ application, the second file that serves a class
can then be used to define or implement the methods. Here is an example:

C# 3.0 Practical Learning II 1067


using System;
using System.Windows.Forms;

public partial class Exercise : Form


{
private void InitializeComponent()
{
btnSubmit = new Button();
Controls.Add(btnSubmit);
}

public Exercise()
{
InitializeComponent();
}
}

public class Program


{
public static int Main()
{
Application.Run(new Exercise());
return 0;
}
}

In Microsoft Visual C#, the name of the first file of a form starts with the
name of the form, followed by a period, followed by Designer, followed by a
period, and followed by the cs extension.

Components Tracking on an Application


As you add and remove components on an application, you need a way to
count them to keep track of what components and how many of them your
application is using. To assist you with this, the .NET Framework provides a
class called Container. This class is defined in the ComponentModel
namespace that is itself part of the System namespace. To use a variable of
this class in your application, declare a variable of type Container. Because
no other part of the application is interested in this variable, you should
declare it private. This can be done as follows:
using System;
using System.Windows.Forms;

public partial class Exercise


{
private Button btnSubmit;
System.ComponentModel.Container components;
}

After this declaration, the compiler can keep track of the components that
are part of the form.

C# 3.0 Practical Learning II 1068


Control Derivation
If you are using a .NET Framework control, you must know the name of the
class on which the control is based (and each control is based on a particular
class). If you have examined the types of classes available but none
implements the behavior you need, you can first locate one that is close to
the behavior you are looking for, then use it as a base to derive a new class.

To derive a class from an existing control, you can use your knowledge of
inheritance. Here is an example:
public class Numeric : System.Windows.Forms.TextBox
{
}

If you want to perform some early initialization to customize your new


control, you can declare a constructor. Here is an example:
public class Numeric : System.Windows.Forms.TextBox
{
public Numeric()
{
}
}

Besides the constructor, in your class, you can add the fields and methods as
you see fit. You can also use it to globally set a value for a field of the parent
class. Once the control is ready, you can dynamically use it like any other
control. Here is an example:
using System;
using System.Windows.Forms;

public class Numeric : System.Windows.Forms.TextBox


{
public Numeric()
{
}
}

public partial class Exercise


{
private Numeric txtBox;
System.ComponentModel.Container components;
}
using System;
using System.Windows.Forms;

public partial class Exercise : Form


{
private void InitializeComponent()
{
txtBox = new Numeric();
Controls.Add(txtBox);

C# 3.0 Practical Learning II 1069


}

public Exercise()
{
InitializeComponent();
}
}

public class Program


{
public static int Main()
{
Application.Run(new Exercise());
return 0;
}
}

This produce:

Control Selection
 

Introduction
When designing an application, you will manipulate the windows controls on a
form. After adding a control to a form, before performing any operation on that

C# 3.0 Practical Learning II 1070


control, you must first select it. You can also manipulate many controls at the
same time. To do that, you will have to select all those controls.
 

Single Control Selection


To select one control on the form, you can simply click it. A control that is
selected indicates this by displaying 8 small squares, also called handles,
around it. Between these handles, the control is surrounded by dotted
rectangles. In the following picture, the selected rectangle displays 8 small
squares around its shape:

After selecting a control, you can manipulate it or change its characteristics,


also called properties.

Multiple Control Selection


To select more than one control on the form, click the first. Press and hold
either Shift or Ctrl. Then click each of the desired controls on the form. If you
click a control that should not be selected, click it again. After selecting the
group of controls, release either Shift or Ctrl that you were holding.

When a group of controls is selected, the last selected control displays 8


square handles around but its handles are white while the others are black.
Another technique you can use to select various controls consists of clicking
on an unoccupied area on the form, holding the mouse down, drawing a fake
rectangle, and releasing the mouse:

C# 3.0 Practical Learning II 1071


Every control touched by the fake rectangle or included in it would be
selected:

Control Deletion
If there is a control on your form but you don't need it, you can remove it from
the application. To delete a control, first select it and then click or press Delete.
You can also right-click a control and click Cut. To remove a group of controls,
first select them, then click or press Delete or right-click the selection and click
Cut.

The Properties Window


 

Introduction

C# 3.0 Practical Learning II 1072


A property is a piece of information that characterizes or describes a control.
It could be related to its location or size. It could be its color, its identification,
or any visual aspect that gives it meaning. The properties of an object can be
changed either at design time or at run time. You can also manipulate these
characteristics both at design and at run times. This means that you can set
some properties at design time and some others at run time.

To manipulate the properties of a control at design time, first select it on the


form. While a control is selected, use the Properties window to manipulate the
properties of the control at design time. To access the Properties window if it is
not visible:

 On the main menu, you can click View -> Properties Window

 On the form, you can right-click anything (either the form itself or any
control positioned on it) and click Properties

 The shortcut to display the Properties window is F4

Description
The Properties window uses the behaviors we reviewed in Lesson 1 about
auto-hiding, docking, floating or tabbing the tools that accompany Microsoft
Visual Studio 2005. This means that you can position it on one side of the
screen or to have it float on the screen as you wish.

The Properties window is divided in 5 sections:

The Properties window starts on top with a title bar, which displays the string
Properties. If the window is docked somewhere, it displays the Window

C# 3.0 Practical Learning II 1073


Position , the Auto-Hide , and the Close buttons on its right side. If the
window is floating, it would display only the Close button.

Under the title bar, the Properties window displays a combo box. The content
of the combo box is the name of the form plus the names of the controls
currently on the form. Besides the technique we reviewed earlier to select a
control, you can click the arrow of the combo box and select a control from
the list:

Under the combo box, the Properties displays a toolbar with 4 buttons.

Under the toolbar, the Properties window displays the list of properties of the
selected control(s). On the right side, the list is equipped with a vertical scroll
bar. The items in the Properties window display in a list set when installing
Microsoft Visual Studio. In the beginning, you may be regularly lost when
looking for a particular property because the list is not arranged in a strict
order of rules. You can rearrange the list. For example, you can cause the
items to display in alphabetic order. To do this, on the toolbar of the
Properties window, click the Alphabetic button . To restore the list, you
can click the categorized button .

Two lists share the main area of the Properties window. When the list of
properties is displaying, the Properties button is clicked . The second is the
list of events. Therefore, to show the events, you can click the Events button
. If the events section is displaying, to show the list of properties, you can
click the Properties button .

Under the list of properties, there is a long bar that displays some messages.
The area is actually a help section that displays a short description of the
property that is selected in the main area of the Properties window.

Accessing the Properties of One or More Controls


Based on a previous description,

 If the Properties window is already displaying, to access the properties of


the form or of a control, simply click it

C# 3.0 Practical Learning II 1074


 If the Properties window is not displaying, to access the characteristics of
an object, right-click either the form or a control on the form and click
Properties

 If the Properties window is not available, to access the characteristics,


click either the form or a control on the form and, on the main menu,
click View -> Properties

When a control is selected, the Properties window displays only its


characteristics:

You can also change some characteristics of various controls at the same
time. To do this, first select the controls on the form and access the
Properties window:

C# 3.0 Practical Learning II 1075


When various controls have been selected:

 The Properties window displays only the characteristics that are common
to the selected controls

 The combo box on top of the Properties window is empty

 Some fields of the Properties appear empty because the various controls
that are selected have different values for those properties

Practical Learning: Introducing the Properties Window

1. To create a new application, on the main menu, click File -> New
Project...

2. In the Templates list, click Windows Application

Set the Name to Exercise4 and click OK

Properties Categories
 

Introduction
Each field in the Properties window has two sections: the property’s name and
the property's value:
 

C# 3.0 Practical Learning II 1076


The name of a property is represented on the left column. This is the official
name of the property. The names of properties are in one word. You can use
this same name to access the property in code.

The box on the right side of each property name represents the value of the
property that you can set for an object. There are various kinds of fields you
will use to set the properties. To know what particular kind a field is, you can
click its name. To set or change a property, you use the box on the right side
of the property’s name: the property's value, also referred to as the field's
value.

Practical Learning: Displaying the Properties Window

 To display the Properties windows, on the main menu, click View ->
Properties Window

Empty Fields

C# 3.0 Practical Learning II 1077


 

By default, these fields have nothing in their value section. Most of these
properties are dependent on other settings of your program. For example, you
can set a menu property for a form only after you have created a menu.

To set the property on such a field, you can type in it or select from a list. 

Practical Learning: Checking Empty Fields

 Click the body of the form.


In the Properties windows, notice that the AccessibleName and the Tag
fields are empty

Text Fields
There are fields that expect you to type a value. Most of these fields have a
default value. Here is an example:

C# 3.0 Practical Learning II 1078


To change the value of the property, click the name of the property, type the
desired value, and press Enter.

While some properties, such as the Text, would allow anything, some other
fields expect a specific type of text, such as a numeric value.

Practical Learning: Checking Text Fields

1. In the Properties windows, click Text and notice that it contains a string
in bold characters

2. Click (Name) and notice that it contains some bold characters

Numeric Fields
Some fields expect a numeric value. In this case, you can click the name of
the field and type the desired value. Here is an example:

. If you type an invalid value, you would receive a message box notifying you
of the error:

When this happens, click OK and type a valid value. If the value is supposed
to be an integer, make sure you don't type it as a decimal number.

C# 3.0 Practical Learning II 1079


Practical Learning: Checking Numeric Fields

1. In the Common Controls section of the Toolbox, click NumericUpDown


and click the form

2. While the control is still selected on the form, in the Properties windows,
click Value and notice that it contains a number string in bold characters

3. Click the DecimalPlaces, the Increment, the Maximum, and the Minimum
fields to see that they contain numeric values:
 

Date-Based Fields
Some fields expect you to enter a date. You must type a valid date
recognized by the operating system and the Regional and Language Settings
in Control Panel. If you enter an invalid date, you would receive an error.

Practical Learning: Checking Date and Time Fields

1. In the Common Controls section of the Toolbox, click DateTimePicker


and click the form

2. While the control is still selected on the form, in the Properties windows,
click Value and notice that it contains a date and time value

C# 3.0 Practical Learning II 1080


3. Click the MinDate and the MaxDate fields to see their values:
 

Expandable Fields
 

Some fields have a + button. This


indicates that the property has a set of sub-properties that actually belong to
the same property and are defined together. To expand such a field, click its +
button and a – button will appear:

C# 3.0 Practical Learning II 1081


To collapse the field, click the – button.

Some of the properties are numeric based, such as the Location or the
Size. With such a property, you can click its name and type two numeric
values separated by a comma. Some other properties are created from an
enumeration or a class. If you expand such a field, it would display various
options. Here is an example from the Font property:

With such a property, you should select from a list.

Practical Learning: Checking Expandable Fields

C# 3.0 Practical Learning II 1082


1. Click an empty area of the form to select the form

2. In the Properties window, click the + button of the Font field to expand
it and notice that it display some previously hidden items

Boolean Fields
 

Some fields can have only a True or


False value. To change their setting, you can either select from the combo
box or double-click the property to toggle to the other value.

Practical Learning: Checking Boolean Fields

1. In the Properties window click Enabled and notice that it displays True

2. Under Font, click Bold and notice that it displays False 

Action Fields
Some fields would require a value or item that needs to be set through an
intermediary action. Such fields display an ellipsis button . When you click

C# 3.0 Practical Learning II 1083


the button, a dialog box would come up and you can set the value for the field.

Practical Learning: Checking Action Fields

1. In the Common Controls section of the Toolbox, click PictureBox and


click the form

2. While the control is still selected on the form, in the Properties windows,
click Image and notice that the field displays an ellipsis button

3. Click the ellipsis button and notice that a dialog box comes up

4. Click Cancel

List-Based Fields
To change the value of some of the fields, you would use their combo box to
display the available values. After clicking the arrow, a list would display:

C# 3.0 Practical Learning II 1084


There are various types of list-based fields. Some of them display just two
items. To change their value, you can just double-click the field. Some other
fields have more than two values in the field. To change them, you can click
their arrow and select from the list. You can also double-click a few times
until the desired value is selected.

Practical Learning: Checking List-based Fields

1. Click an empty area of the form to select the form

2. In the Properties window, click FormBorderStyle and notice that it


displays an arrow button of a combo box

3. Press Alt and the down arrow key to display the list

4. Press Esc

Area-Selection Fields
Some properties provide a window from where you can select the desired
option. The field primarily displays the arrow of a combo box. To use the
field, you click the arrow of the combo box and the window appears. Here are
examples:

C# 3.0 Practical Learning II 1085


After expanding the window, you can select the desired option. We will
eventually review them.

Practical Learning: Checking Area-Selection Fields

1. On the form, click one of the controls

2. In the Properties window, click Dock and click the arrow of its combo box

Notice the window that comes up and press Esc

C# 3.0 Practical Learning II 1086

You might also like