25

NET Windows Development - Everyday Tips, Tricks & Optimization - Krasis Press

Embed Size (px)

DESCRIPTION

Foreword by Lisa Feigenbaum, Visual Studio Program Manager, Microsoft Corporation.If you develop .NET applications for a living, then you need to buy this book!Some of the topics that we cover are:• Special techniques for accessing data• New features in Windows 7• Using Graphics, Serialization and Reflection• Various techniques that should be well-known, but aren’t.• Tips and tricks for Windows Forms applications Most tips can be used under all versions of Visual Studio. Whenever a specific minimum version is needed, it is noted in the text. A few specific examples make use of features that are new to Visual Studio 2010.

Citation preview

Page 1: NET Windows Development - Everyday Tips, Tricks & Optimization - Krasis Press
Page 2: NET Windows Development - Everyday Tips, Tricks & Optimization - Krasis Press

.NET Windows Development

Everyday Tips, Tricks & Optimization

Alberto Población

Page 3: NET Windows Development - Everyday Tips, Tricks & Optimization - Krasis Press

.NET WINDOWS DEVELOPMENT - EVERYDAY TIPS, TRICKS &

OPTIMIZATION

© KRASIS CO NSULTING S.L. 2 0 1 0

www.krasis.com

ALL RIGHTS RESERVED. NO PART O F THIS BO O K MAY BE REPRO DUCED, IN ANY

FO RM O R BY ANY MEANS, WITHO UT PERMISSIO N IN WRITING FRO M THE

PUBLISHER.

ISBN: 978-84-935489-3-3

PRINTED IN THE UNITED STATES O F AMERICA

Notice of Liability

The author and publisher have made every effort to ensure the accuracy of the

information herein. However, the information contained in this book is sold without

warranty, either express or implied. Neither the authors and Krasis Consulting S.L.,

nor its dealers or distributors, will be held liable for any damages to be caused either

directly or indirectly by the instructions contained in this book, or by the software or

hardware products described herein.

Trademark Notice

Rather than indicating every occurrence of a trademarked name as such, this

book uses the names only in an editorial fashion and to the benefit of the trademark

owner with no intention of infringement of the trademark.

Page 4: NET Windows Development - Everyday Tips, Tricks & Optimization - Krasis Press

Acknowledgments

First, I would like to give my thanks to Jose Manuel Alarcón, who suggested that I should

write this book, followed its progress, and encouraged me to go on until it was complete.

Before I started writing this book, I had in my hands a lot of short texts and coding examples

that I had created while answering questions in public forums or presenting examples in

training courses. I give my thanks to the people who asked the questions that prompted me to

create these examples and those who participated in the discussions that allowed me to refine

them.

Some of those pieces have served me as inspiration more than once, since I based on them a

few examples presented in this book and they also supported a few short articles that I

published in the magazine “dotNetMania.” I would like to give a special thank-you to its

editor, Paco Marín, who gave me permission to reuse here some of those ideas.

And last, but not least, I thank my wife, who encouraged me while I was writing and helped

me find the time to write when other obligations seemed to always keep me away from this

task.

Page 5: NET Windows Development - Everyday Tips, Tricks & Optimization - Krasis Press
Page 6: NET Windows Development - Everyday Tips, Tricks & Optimization - Krasis Press

Contents

FOREWORD ........................................................................................................... ix

PREFACE ................................................................................................................ xi

ACCESSING DATA ...................................................................................................... 1 1.- introduction .................................................................................................................................. 1 2.- Using Multiple Active Record Sets .......................................................................................... 1

2.1.- The problem...................................................................................................................... 2 2.2.- First solution ..................................................................................................................... 3 2.3.- Another solution .............................................................................................................. 4 2.4.- The MARS solution ......................................................................................................... 5

3.- Using Asynchronous server calls ............................................................................................. 6 3.1.- The problem...................................................................................................................... 7 3.2.- First solution: Launch a Thread .................................................................................... 8 3.3.- An alternative: Use the ThreadPool ......................................................................... 12 3.4.- Another alternative: Asynchronous delegates ....................................................... 13 3.5.- At last: Asynchronous ADO.NET methods............................................................ 15 3.6.- A further alternative: BackgroundWorker ............................................................. 17 3.7.- And yet another one: The Task class ....................................................................... 18

4.- Importing large amounts of data ............................................................................................ 19 4.1.- The problem.................................................................................................................... 20 4.2.- The solution .................................................................................................................... 21 4.3.- Further improvement ................................................................................................... 22 4.4.- Mapping columns ............................................................................................................ 22

5.- Efficiently accessing Large Objects in the database ........................................................... 23 5.1.- Reading LOBs from a database .................................................................................. 24 5.2.- Writing LOBs to a database ........................................................................................ 27

6.- Beware of SQL Injection attacks ........................................................................................... 29

NEW FEATURES IN WINDOWS 7 .............................................................................. 35 1.- introduction ................................................................................................................................ 35 2.- The Windows API Code Pack................................................................................................ 35 3.- Controlling the new Taskbar .................................................................................................. 37

3.1.- Examining the taskbar ................................................................................................... 38 3.2.- Configuring the AppId .................................................................................................. 38 3.3.- The Jump List .................................................................................................................. 39

3.3.1.- Associating the file types with the application ............................................... 41 3.3.2.- Programming the Jump List ................................................................................ 42 3.3.3.- Tasks in the Jump List .......................................................................................... 43

3.4.- Icon overlays ................................................................................................................... 45 3.5.- Displaying progress in a taskbar button ................................................................... 45

Page 7: NET Windows Development - Everyday Tips, Tricks & Optimization - Krasis Press

vi .NET Windows Development Everyday Tips, Tricks & Optimization

4.- Using Libraries ............................................................................................................................ 47 4.1.- Using the Common File Dialogs ................................................................................ 49 4.2.- Consuming the contents of libraries ........................................................................ 51 4.3.- Manipulating libraries .................................................................................................... 52

5.- Elevating privileges .................................................................................................................... 55 6.- Enabling Federated search on your application data ........................................................ 62

6.1.- The search handler ........................................................................................................ 64 6.2.- The image handler ......................................................................................................... 68 6.3.- The information page.................................................................................................... 69 6.4.- The search connector .................................................................................................. 71

USING GRAPHICS ..................................................................................................... 73 1.- introduction to GDI+ ............................................................................................................... 73

1.1.- First example .................................................................................................................. 73 1.2.- The System.Drawing namespace ............................................................................... 74 1.3.- The Graphics Object .................................................................................................... 75 1.4.- Pens ................................................................................................................................... 76 1.5.- Brushes ............................................................................................................................. 77 1.6.- Fonts ................................................................................................................................. 78 1.7.- Colors ............................................................................................................................... 79 1.8.- The Point and Size Structures .................................................................................... 79 1.9.- The Rectangle Structure .............................................................................................. 80 1.10.- Drawing Lines ................................................................................................................ 81 1.11.- Drawing Rectangles and other shapes .................................................................... 82 1.12.- Drawing Pie Charts ...................................................................................................... 84 1.13.- Drawing Bitmaps and Icons ....................................................................................... 85 1.14.- Summary ......................................................................................................................... 85

2.- Displaying Graphics on Windows Forms ............................................................................ 85 3.- Creating a Control that paints itself ..................................................................................... 89 4.- Using Owner-Draw mode in existing controls ................................................................. 93 5.- Custom Printing with GDI+ ................................................................................................... 99 6.- Dynamic graphics in a Web Page ........................................................................................ 109

CREATIVE USE OF SERIALIZATON ........................................................................... 115 1.- General introduction to Serialization ................................................................................. 115

1.1.- Runtime Serialization .................................................................................................. 116 1.2.- XML Serialization ......................................................................................................... 119

2.- Using Serialization to save the state of a form ................................................................ 123 2.1.- A simple approach ....................................................................................................... 124 2.2.- A more general solution ............................................................................................ 126

3.- Cloning objects by means of Serialization ......................................................................... 132 3.1.- Copying Reference-types ........................................................................................... 132 3.2.- Cloning ........................................................................................................................... 133 3.3.- Applying Serialization .................................................................................................. 137

4.- Using XML Serialization to read and write XML files that conform to a schema .. 137 5.- Storing XML in SQL Server .................................................................................................. 143

SOME USES FOR REFLECTION ................................................................................. 151

Page 8: NET Windows Development - Everyday Tips, Tricks & Optimization - Krasis Press

Contents vii

1.- General introduction to Reflection ..................................................................................... 151 1.1.- Metadata ......................................................................................................................... 151 1.2.- Assemblies ..................................................................................................................... 155 1.3.- Types in an Assembly .................................................................................................. 155 1.4.- Examining Types ........................................................................................................... 156 1.5.- Obtaining a System.Type............................................................................................ 158 1.6.- Creating an instance of a Type ................................................................................. 158 1.7.- Binding and Invocation ................................................................................................ 161

2.- Solving Assembly Load Problems ........................................................................................ 163 2.1.- The Fusion process ..................................................................................................... 163 2.2.- Locating a Referenced assembly .............................................................................. 164 2.3.- Adding a Strong Name ............................................................................................... 166 2.4.- Other options in the configuration file .................................................................. 168 2.5.- Debugging the Fusion process .................................................................................. 169

3.- Loading and invoking Assemblies dynamically .................................................................. 171 4.- Compiling expressions on-the-fly ........................................................................................ 177 5.- Loading and Unloading Assemblies with AppDomains .................................................. 181 6.- Instancing classes from a string ............................................................................................ 184

VARIOUS TECHNIQUES THAT SHOULD BE WELL-KNOWN, BUT SOMETIMES AREN’T.... 189 1.- Reading and writing text files with non-English characters........................................... 189

1.1.- Finding out the problem ............................................................................................. 189 1.2.- What is going on? ........................................................................................................ 190 1.3.- Using Encodings ............................................................................................................ 192 1.4.- Performing the conversions explicitly .................................................................... 195

2.- Ensuring that a form is only opened once ......................................................................... 195 3.- Communicating from a control to its container ............................................................. 198

3.1.- The wrong approach ................................................................................................... 199 3.2.- The right way to do it ................................................................................................. 200

4.- Locking records in a database .............................................................................................. 205 5.- Never forget to close your open connections ................................................................ 209

A FEW TIPS FOR WINDOWS FORMS APPLICATIONS ............................................... 213 1.- Displaying an icon in the Notification Area ...................................................................... 213

1.1.- The NotifyIcon component ....................................................................................... 213 1.2.- Balloon Tips ................................................................................................................... 215 1.3.- Context Menu .............................................................................................................. 216

2.- Complex Resizable Forms ..................................................................................................... 218 2.1.- Using code to rearrange the contents of the form ............................................. 219 2.2.- The Anchor and Dock properties ........................................................................... 220 2.3.- The TableLayoutPanel control ................................................................................. 222 2.4.- The FlowLayoutPanel control ................................................................................... 225

3.- Using Dialogs ............................................................................................................................ 227 3.1.- Traditional dialogs ........................................................................................................ 227 3.2.- Task dialogs in Windows 7........................................................................................ 232

4.- Non-Rectangular Forms ......................................................................................................... 236 5.- Processing all the Controls in a Form ................................................................................ 240

5.1.- Implementing a first example .................................................................................... 241

Page 9: NET Windows Development - Everyday Tips, Tricks & Optimization - Krasis Press

viii .NET Windows Development Everyday Tips, Tricks & Optimization

5.2.- A more complex example ......................................................................................... 244

INDEX .................................................................................................................. 247

Page 10: NET Windows Development - Everyday Tips, Tricks & Optimization - Krasis Press

ix

Foreword

The Microsoft .NET Framework contains thousands of libraries to help with just

about any modern development task. You can use the .NET Framework to access data,

create a user interface, run algorithms or consume a service. The challenge as a .NET

developer becomes to learn what types of libraries are available, how to use them and

when. This book helps guide Windows® developers through common questions for a

variety of common .NET development scenarios.

Why focus on Windows development? With more than a billion clients in the world

today, Windows is by far the largest available platform. Windows 7, in particular, has

been the fastest growing and most popular release of Windows yet. See the Windows 7

chapter in this book to learn how your applications can light up on this huge, growing

platform. A number of the tips in this book are also relevant to other .NET application

types.

As a Visual Studio community program manager, I have the opportunity to interact

with many customers, including the Microsoft Most Valuable Professional (MVP)

program. The MVP Program honors Microsoft technology experts for their impact in

the community. Alberto Población has been awarded as a C# MVP because of his great

impact teaching others about .NET development, both as a trainer as well as a top

answerer in the newsgroups and forums.

Tips and tricks content is always incredibly popular because of its immediate

practical use. It is also very personal, based on the author‟s experience and

prioritization. Alberto‟s selections in this book draw on nearly 30 years of development

and reflect the top questions raised in his interactions with .NET users. Reading this

book will help you expand your toolset, complete tasks more quickly, and write better

and more resilient code. Alberto‟s writing style is easy to follow and engaging to read.

You can keep it on your shelf as a reference or read it cover to cover as a novel.

So, pack this guide with you, give it a read and add some new tricks to your

toolbox!

Lisa Feigenbaum Community Program Manager

Microsoft Visual Studio

Page 11: NET Windows Development - Everyday Tips, Tricks & Optimization - Krasis Press
Page 12: NET Windows Development - Everyday Tips, Tricks & Optimization - Krasis Press

xi

Preface

ABOUT THIS BOOK

Most software developers typically spend their time developing line-of-business

(LOB) applications, such as accounting, inventory or payroll. These applications

usually involve presenting forms that capture data, save the data to a database, and

recover and display the data, as well as generating lots of reports.

Occasionally, a different feature will be needed in a program. It may be necessary to

display a custom graphic, or to generate a specialized report that cannot be generated

by the standard reporting engine of choice. Perhaps we require a universal mechanism

for saving the state of all our forms, or we might wish to enhance our user interface by

means of some of the features in the latest version of Windows. Any of the required

techniques would probably be straightforward for someone who specializes in such

tasks, but may not be evident for a developer of LOB applications who spends most of

his or her time developing code to display forms that access a database.

In this book, we intend to present a few useful techniques for performing various

tasks that in many cases will not be familiar to our intended audience, but may come

handy when some new feature or enhancement is needed in a LOB application.

Some of our chapters present features of the Framework that are not widely known

due to their very specialized use. In other cases, we present features that in our opinion

should be well known; however, when examining the questions that are frequently

repeated in developer forums, and the small number of replies that such questions

receive, we conclude that these topics are not as well known as they deserve.

Therefore, we have chosen to also cover some of these “simpler” topics.

ABOUT THE CODING EXAMPLES

Most of our examples are based on Windows Forms applications, although we do

include a few tips that are specific to Web Forms. However, the majority of the topics

that we present refer to the usage of the Framework Class Libraries (FCL). These

libraries operate in the same way regardless of the technology that is used for the user

interface, and therefore the techniques that we present can be used not only in

Windows Forms, but also in Web Forms, ASP.NET MVC, Windows Presentation

Foundation, or even Silverlight applications.

The examples in this book are written in C#. However, since they deal with the

FCL, most of the concepts that we present are the same regardless of the language that

Page 13: NET Windows Development - Everyday Tips, Tricks & Optimization - Krasis Press

xii .NET Windows Development Everyday Tips, Tricks & Optimization

you use to access them. Therefore, they should be useful for developers writing code in

VB.NET or any other .Net language.

If you wish to run the examples without having to type them from the book, you can

download the completed sample projects from the website of the publisher.

Most of the projects were done with Visual Studio 2008, but will migrate without

effort to Visual Studio 2010. A small number of the samples, mainly those that present

some of the latest features in Windows or in Visual Studio, were done with Visual

Studio 2010, and are not directly compatible with earlier versions.

And now, with no further ado, let‟s go ahead into the first chapter.

Page 14: NET Windows Development - Everyday Tips, Tricks & Optimization - Krasis Press

189

CHAPTER

This chapter deals with some miscellaneous subjects that, supposedly,

should be familiar to all developers. However, after having examined lots of

code and answered questions from many developers, we have concluded that,

unfortunately, these matters are not as obvious or as well-known as would be

expected.

1.- READING AND WRITING TEXT FILES WITH NON-

ENGLISH CHARACTERS

Many developers whose native language is English never deal with text that

contains characters other than those in the ASCII table. This encoding uses 7 bits to

codify a set of symbols, numbers and all the letters that are used in English. However,

other languages use additional characters such as letters with diacritical marks (áèü) or

additional symbols (åøñ). And we are not even speaking about non-Latin alphabets

such as Greek, Russian or Chinese.

1.1.- Finding out the problem

A typical way to read a text file uses a StreamReader, in a way that is similar to

what we see in the following code fragment:

using System.IO;

...

using (StreamReader sr = new StreamReader(filename))

{

string s = sr.ReadLine();

textBox1.Text = s;

}

Various techniques that

should be well-known,

but sometimes aren’t

6

Page 15: NET Windows Development - Everyday Tips, Tricks & Optimization - Krasis Press

190 .NET Windows Development - Everyday Tips, Tricks & Optimization

This will work well with a file that only contains ASCII characters. But let‟s do an

experiment. Open Notepad, type-in a sentence that contains some foreign characters,

and save it into a file on disk. For instance:

Figure 1.- Non-English text in Notepad

Note: if you are using a U.S. keyboard, it does not directly generate any of these

special characters. You can insert them from the “Character Map” utility that is usually

found under Start -> All Programs -> Accessories -> System Tools. You can also press

the Alt key, enter the numeric code for the character on the numeric keypad, and

release the Alt key. For instance, the “é” character that we used can be entered as

Alt+130.

Now, run the piece of code above, so that it reads the file that was saved in

Notepad. You will note that the non-ASCII characters come out wrong:

Figure 2.- The text that is read from the file

As you can see, the textbox shows small rectangles in place of the “special”

characters.

1.2.- What is going on?

Notepad saved the file using an encoding named “ANSI” (the “Save As...” dialog

offers other choices, but ANSI is selected by default). This encoding uses 8 bits to

encode each character. The first 127 characters match the ASCII table, so there is no

problem when reading pure English text. But the “top” 128 characters represent various

symbols such as the “é” and “¿” that we typed in our sample. The specific mapping of

characters depends on the regional version of Windows. The example above was run

Page 16: NET Windows Development - Everyday Tips, Tricks & Optimization - Krasis Press

Various techniques that should be well-known, but sometimes aren’t 191

on an operating system that was using the “Western European” character set, also

known as “Windows-1252”.

If you wish to see the actual codes that were written into the file, you can open it

with a binary editor. You can do this from Visual Studio if you add the file into the

project. Then, right-click on it in Solution Explorer and select Open With -> Binary

Editor.

Figure 3.- Hexadecimal content of the ANSI text file

Here you can see, for instance, that the “é” was encoded as 0xE9.

All Strings in .Net are Unicode, and they are stored in memory using the UTF-16

encoding, which encodes each character in 16 bits (well, this is only true for characters

in the Basic Multilingual Plane, but in practice it is unlikely that you will be using any

other of the Unicode planes). This is enough for encoding most of the characters in all

languages, so you do not have to worry about encodings when manipulating character

strings inside your programs.

At some point, when you are reading the 8-bit data from the file into the Unicode

String in memory, there has to be a conversion that “translates” the characters from one

encoding into the other. When reading the file with a piece of code like the one in our

first example, the StreamReader itself performs the conversion. By default, it tries to

interpret the file as UTF-8. This is an encoding that stores Unicode characters using 8-

bit data. The first 127 characters are stored in a single byte, and they match the ASCII

table, so this process is not apparent when reading English text. However, “special”

characters are stored using more than one byte. The first byte serves as a sort of

“prefix” to indicate that something special comes next. This is what our file would

contain if saved as UTF-8:

Figure 4.- Hexadecimal content of the UTF8 text file

As you can see, the “é” is now encoded as 0xC3 0xA9, which is quite different from

its ANSI encoding.

When the StreamReader attempts to interpret the file according to the UTF-8

encoding, but instead finds characters encoded as ANSI, it fails to interpret them

correctly. Sometimes, a character is misinterpreted so that a different character is

shown instead. In other cases, the specific combination of bits may not even

correspond to any character in the target encoding, so a small rectangle is displayed (as

we saw earlier) to indicate the error.

Page 17: NET Windows Development - Everyday Tips, Tricks & Optimization - Krasis Press

192 .NET Windows Development - Everyday Tips, Tricks & Optimization

1.3.- Using Encodings

In order to interpret correctly the contents of the file, we need to tell the

StreamReader which is the encoding for the file that it is reading. This can be done by

means of a parameter of type System.Text.Encoding that can be passed to the

constructor:

using System.Text;

...

Encoding encoding = Encoding.GetEncoding(1252);

using (StreamReader sr = new StreamReader(filename, encoding))

{

string s = sr.ReadLine();

textBox1.Text = s;

}

The preceding code would display properly the content of the file, if it was written

using the Western European (“Windows-1252”) character set.

The Encoding class has static methods that provide the most usual encodings, such

as Encoding.UTF8 or Encoding.ASCII. It also has a GetEncoding method that can

obtain an encoding from its number (as shown above) or from its name, such as

Encoding.GetEncoding("Windows-1252").

There is no reliable way to determine the encoding that was used to create a file.

You need to be familiar with the application that created the file, and the platform on

which it was run, so that you can deduce the Encoding that you need to specify when

opening the file. If you use the wrong encoding, the characters will come out all wrong.

For instance, if you thought that our example ANSI file was created on a Greek version

of Windows, you might try to open it using encoding “Windows-1253” (which is the

Greek encoding). The code would be exactly the same except that you would change

the number for the encoding:

Encoding enc = Encoding.GetEncoding(1253);

When running the program, the wrong characters would be displayed:

Figure 5.- Wrong text read from the file

Page 18: NET Windows Development - Everyday Tips, Tricks & Optimization - Krasis Press

Various techniques that should be well-known, but sometimes aren’t 193

The same binary codes in the file on disk have now been interpreted as Greek

characters, since we told the StreamReader to use that encoding; this is why we are

seeing an omega and an iota instead of the original characters that we wrote into the

file. Of course, an analogous failure when reading the text would occur if the file had

actually been written in Greek (1253) and we tried to interpret it as Western European

(1252). So it is important to specify the correct encoding when accessing the file.

Up to this point, we have talked about using .Net code for reading a file that was

created with an external tool, but the same applies when writing a file that needs to be

in a specific format so that it can be read properly by a different application. Normally,

you would write a text file with a StreamWriter:

using (StreamWriter sw = new StreamWriter(filename))

{

sw.WriteLine(textBox1.Text);

}

By default, the StreamWriter translates the Unicode string in memory (represented

by textBox1.Text in the preceding example) into an equivalent UTF-8 sequence of

bytes that is written into the file. If we run this code and then open the file with

Notepad, the text will display correctly because the file contains a prefix at the

beginning that specifies the way in which it is encoded (you can see the prefix in the

hexadecimal dump in figure 4). Notepad recognizes this prefix and interprets the file

accordingly. However, if the file needs to be open by an application that does not

understand this convention and tries to interpret the file according to a pure 8-bit

encoding, the result will be all wrong. For instance, this is what you see if you display

the file in a Command Prompt window:

Figure 6.- UTF8 file in a Command Prompt window

Notice how the file prefix is displayed as a sequence of strange characters and the

pair of bytes that encodes each of our special characters is interpreted as a pair of

different characters.

If we want the file to display correctly, we need to save it using the same encoding

that is expected by the program that is going to interpret it later. In this case, this could

be, for instance, encoding 850 (“Western European DOS”) or 437 (“OEM United

States”), depending of the version of Windows. The encoding is passed in the

constructor of the StreamWriter, similarly to what we did for the StreamReader:

Page 19: NET Windows Development - Everyday Tips, Tricks & Optimization - Krasis Press

194 .NET Windows Development - Everyday Tips, Tricks & Optimization

Encoding enc = Encoding.GetEncoding(850);

using (StreamWriter sw = new StreamWriter(filename, false, enc))

{

sw.WriteLine(textBox1.Text);

}

If we write the file using this code, it will display correctly in the Command Prompt

window, as shown in the following figure:

Figure 7.- Displaying a correctly encoded file

Of course, now it will fail to display correctly if it is opened with Notepad, since

this program expects a different encoding. Once more, we are reminded that it is

important to know which program is going to use our file, so that it can be saved with

the expected encoding.

So, which encoding should you use if you are writing a program that needs to save

text files and is later going to read them?

If you are in control of both the reading and writing processes, you can use any

encoding as long as it is the same one for reading and for writing. If you wish to

support the whole range of Unicode characters without loss of information, you should

use one of the encodings that support Unicode. If your text contains mostly ASCII

characters, UTF-8 is probably the best choice, since it will encode the majority of

characters using only one byte. It also happens to be the default if you do not specify

any encoding for the StreamReader and StreamWriter.

If the program needs to be compatible with legacy Windows applications, you

probably want to use one of the ANSI encodings. As we saw earlier, there are several

variations depending on the locale of the operating system. In most cases, you will

want your program to use the default encoding, so that the files are compatible with

other locally installed applications. You can get the operating system's current ANSI

code page by means of System.Text.Encoding.Default.

Encoding enc = Encoding.Default;

StreamWriter sw = new StreamWriter(filename, false, enc);

...

The documentation for the System.Text.Encoding class lists the available

encodings.

Page 20: NET Windows Development - Everyday Tips, Tricks & Optimization - Krasis Press

Various techniques that should be well-known, but sometimes aren’t 195

1.4.- Performing the conversions explicitly

In all the preceding explanations, we just passed an Encoding to the StreamReader

or StreamWriter and we let these classes perform all the character encoding and

decoding. If you are familiar with the operation of the classes in the System.IO

namespace, you know the StreamReader and StreamWriter merely serve as

intermediaries between your code and a Stream. The Stream reads and writes arrays of

bytes, and the StreamReader and StreamWriter translate those bytes into or from

Strings, applying the adequate encoding in the process.

Those arrays of bytes need not always come from a file. Maybe you are receiving

them from a TCP socket, or you need to save them into a BLOB in a database. In any

case, it is conceivable that you may need to write the code that transforms a String into

an array of bytes with a specific encoding, or vice versa. This can be done by means of

the methods GetBytes and GetString of the Encoding class.

Encoding enc = Encoding.UTF8;

//Convert string to byte[]

string theText = ...;

byte[] converted = enc.GetBytes(theText);

//Convert byte[] to string:

byte[] b = ...;

string s = enc.GetString(b);

To summarize: the next time that you write an application that might need to handle

international text, keep in mind that not necessarily every character maps to one byte,

and even if you can fit the whole character set that the application uses into 8 bits, there

are different ways to perform this mapping. Therefore, you will need to devote a little

bit of time to consider the Encoding that you will use, and apply it at the appropriate

places.

2.- ENSURING THAT A FORM IS ONLY OPENED ONCE

This is quite simple, but you would be surprised at the number of times that this

question appears in programming forums, even from people who are reasonably

experienced at developing windows forms applications.

Typically, the author of the question is writing an application that has a main form,

possibly an MDI container, which has a button or menu option for opening a second

form (usually, but not necessarily, an MDI child). Of course, opening the secondary

form is quite easy:

private void ShowNewForm(object sender, EventArgs e)

{

Form1 childForm = new Form1();

childForm.MdiParent = this;

childForm.Text = "Window " + childFormNumber++;

childForm.Show();

}

Page 21: NET Windows Development - Everyday Tips, Tricks & Optimization - Krasis Press

196 .NET Windows Development - Everyday Tips, Tricks & Optimization

By the way, this is (almost) the default code provided by Visual Studio when you

add a new MDI form to a Windows Forms project.

However, if you press repeatedly the button to open a new form, several copies of

the form will be opened, because each time a new instance of Form1 is created and

shown.

A first approach to avoid this situation is to keep a reference to the child form in a

class variable and verify whether it is initialized before opening a second copy of the

form:

private Form1 childForm = null;

private void ShowNewForm(object sender, EventArgs e)

{

if (childForm == null)

{

childForm = new Form1();

childForm.MdiParent = this;

childForm.Show();

}

else

{

childForm.Show();

if (childForm.WindowState == FormWindowState.Minimized)

childForm.WindowState = FormWindowState.Normal;

childForm.BringToFront();

}

}

If the reference is null, we create a new form and show it. If it is not null, we take

whatever actions are needed to make it visible (for instance, it could be minimized or

hidden beneath other forms). This works, but it has a drawback: What if the user closes

the form? The reference will still be not null, so the program will not open the form

again.

There are several possible solutions to this situation. The first is to check not only

whether the reference to the child form is null, but also if it has been disposed:

if (childForm == null || childForm.IsDisposed)

{

childForm = new Form1();

childForm.MdiParent = this;

childForm.Show();

}

else ...

This works, in general, but is not completely reliable because it depends on the form

being disposed when it is closed. However, there are some circumstances when this

does not happen. For instance, the documentation asserts that if an MDI form is hidden

and then its Close method is called, the form is not disposed.

Another alternative is to connect a handler to the FormClosed event, and use this to

clear the reference to the form:

private Form1 childForm = null;

private void ShowNewForm(object sender, EventArgs e)

Page 22: NET Windows Development - Everyday Tips, Tricks & Optimization - Krasis Press

Various techniques that should be well-known, but sometimes aren’t 197

{

if (childForm == null)

{

childForm = new Form1();

childForm.MdiParent = this;

childForm.FormClosed +=

new FormClosedEventHandler(childForm_FormClosed);

childForm.Show();

}

else

{

childForm.Show();

if (childForm.WindowState == FormWindowState.Minimized)

childForm.WindowState = FormWindowState.Normal;

childForm.BringToFront();

}

}

void childForm_FormClosed(object sender, FormClosedEventArgs e)

{

childForm = null;

}

Yet another option is to loop over all the child forms trying to find the one that we

wish to show. If found, we make it visible; otherwise, a new form is created:

private void ShowNewForm(object sender, EventArgs e)

{

foreach (Form f in this.MdiChildren)

{

if (f is Form1)

{

f.Show();

if (f.WindowState == FormWindowState.Minimized)

f.WindowState = FormWindowState.Normal;

f.BringToFront();

return;

}

}

Form1 childForm = new Form1();

childForm.MdiParent = this;

childForm.Show();

}

This is perhaps easier to understand, since it does not require connecting an event,

but it may be a little less efficient due to the need for looping over all the forms. Note

that this last method only works for MDI forms, while the previous ones would be

valid for any kind of form. If you want to use this method with any arbitrary forms, you

can substitute Application.OpenForms for this.MdiChildren.

It wasn‟t that difficult, was it? So, why are there so many developers who ask about

this subject? Well, a possible reason is that many of them are programmers who

previously developed applications with VB6 (or earlier), and have migrated to .Net.

Old VB6 had a feature that is no longer present in .Net: For every form in the project,

the compiler automatically issued a statement like this one:

Public Form1 As New Form1

Page 23: NET Windows Development - Everyday Tips, Tricks & Optimization - Krasis Press

198 .NET Windows Development - Everyday Tips, Tricks & Optimization

This led many developers to not make the distinction between the class and the

instance, because they always had a reference to an instance with the same name as the

class. Also, declaring something “...As New type” had an implication that no longer

holds true in .Net, namely, “every time the object is accessed, verify that it is not

Nothing, and if it is, automatically create a new instance”. Therefore, it was easy to

simply do “Form1.Show” at any time, and it always showed the same form. This will

not work in .Net, and it causes much confusion for VB6 programmers, including their

failure to understand why Form1.TextBox1 doesn‟t work. So the important lesson for

developers who have migrated in this way is that they need to understand the difference

between a class and an instance of that class, and that the name of a form cannot be

used implicitly to reference an instance of that form.

3.- COMMUNICATING FROM A CONTROL TO ITS

CONTAINER

This is another task that should be simple, but some developers try to solve it in

ways that are convoluted or inelegant. For illustration, we are going to work on an

example that consists of a Windows form that contains a user control, but the same

principles would also apply to a web page that contains user control or a server control,

or to a master page that hosts a content page.

Consider a form that contains a user control. The developer wants to perform some

action on the form when something happens on the control. For example, the control

contains a button, and the goal is to present some text in a textbox contained in the

form (outside of the user control) when a button in the user control is clicked.

Figure 8.- Example application

Page 24: NET Windows Development - Everyday Tips, Tricks & Optimization - Krasis Press
Page 25: NET Windows Development - Everyday Tips, Tricks & Optimization - Krasis Press