处理 SSI 文件时出错
 
 
日 历
 
 
<<  < 2006 - >  >>
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28
 
 
公 告
 
 

 
 
登 陆
 
 

 
 
我 的 分 类
 
   
 
最 新 日 志
 
   
 
最 新 回 复
 
   
 
留 言 板
 
   
 
BLOG 信 息
 
 
  • 日志:58
  • 评论:-1
  • 留言:3
  • 访问:
 
 
友 情 连 接
 
  处理 SSI 文件时出错
 
 
 

Visual Studio 会侵蚀我们的思想吗?- 续

Interactive Design

Most of the really innovative interactive design stuff found its first expressions in the Windows-based versions of Visual Basic, and here’s where I started becoming nervous about where Windows programming was headed. Not only could you move a button onto your form, and interactively position and size it just the way you wanted, but if you clicked on the button, Visual Basic would generate an event handler for you and let you type in the code.

This bothered me because Visual Basic was treating a program not as a complete coherent document, but as little snippets of code attached to visual objects. That’s not what a program is. That’s not what the compiler sees. How did one then get a sense of the complete program? It baffled me.

Eventually, the interactive design stuff found its way into development with C++ and the Microsoft Foundation Classes, and there, I truly believe, code generation was used to hide a lot of really hairy MFC support that nobody wanted to talk about.

For an author who writes programming books, all this stuff presents a quandary. How do you write a programming tutorial? Do you focus on using Visual Studio to develop applications? Frankly, I found it very hard to write sentences like “Now drag the button object from the tool box to your dialog box” and still feel like I was teaching programming. I never wrote about C++ and MFC, partially because MFC seemed like a light wrapper on the Windows API and barely object oriented at all. I continued to revise later editions of Programming Windows under the assumption that its readers were programmers like me who preferred to write their own code from scratch.

Bye, Bye, Resource Script

I first started looking at beta .NET 1.0 and Windows Forms in the summer of 2000, and it was clearly more object oriented than MFC could ever be. I liked it. I was also intrigued that the resource script had entirely disappeared. You created and assembled controls on dialog boxes — now subsumed under the more global term of “forms” — right there in your code. Of course, even in Windows 1.0, you could create controls in code, and the first edition of Programming Windows has some examples. But it just wasn’t very pleasant, because every control creation involved a call to the 11-argument CreateWindow function. But creating controls in code in Windows Forms was a snap.

What’s nice about creating and manipulating controls in code is that you’re creating and manipulating them in code. Suppose you want a column of ten equally-spaced buttons of the same size displaying Color names. In a program, you can actually store those ten Color values in one place. It’s called an array. There’s also an excellent way to create and position these ten buttons. It’s called a for loop. This is programming.

But Visual Studio doesn’t want you to use arrays or loops to create and position these buttons. It wants you to use the designer, and it wants to generate the code for you and hide it away where you can’t see it.

Almost twenty years after the first Dialog Editor, Visual Studio is now the culprit that generates ugly code and warns you not to mess with it.

If you do try to read this code, it’s not that easy because every class and structure is preceded by a full namespace:

System.Windows.Forms.Button button1 = new System.Windows.Forms.Button();

Of course, we know why Visual Studio needs to do this. In theory, it’s possible for you to add to the Visual Studio toolbox another control named Button from another DLL with another namespace, and there must be a way to differentiate them.

As Visual Studio is generating code based on the controls you select, it gives the controls standard names, such as button1, button2, button3, label1, label2, label3, textBox1, textBox2, textBox3.

Of course, Visual Studio lets you change that variable name. You change the Name property of the control, and that becomes not only the Name property of the button object, but also the button variable name.

Do programmers actually do this? I’m sure some do, but I’m also sure many do not. How do I know? Take a look at some of the sample code that comes out of Microsoft. There you’ll see button1, button2, button3, label1, label2, label3, etc. Any yet, everyone agrees that one of the most important elements of writing self-documenting code is giving your variables and objects meaningful names.

If Visual Studio really wanted you to write good code, every time you dragged a control onto your form, an annoying dialog would pop up saying “Type in a meaningful name for this control.” But Visual Studio is not interested in having you write good code. It wants you to write code fast.

While I’m on the subject of variable names, I should say something good about Visual Studio. Visual Studio 2005 has a totally splendid variable-renaming facility. You know how sometimes you really want to rename a variable to be more in tune with its actual function in the program but you’re afraid to because of possible side effects of search-and-replace? Well, this new variable-renaming avoids all that, and it will also tell you if you’re renaming something to an existing name. I hope people take advantage of this to rename their controls to something other than the Visual Studio defaults.

Overused Fields

Another problem with Visual Studio’s generated code is that every control is made a field of the class in which it is created. This is a hideous programming practice, and it really bothers me that programmers may be looking at the code generated by Visual Studio to learn proper programming technique, and this is what they see.

In the pre-object oriented days of C programming, we had local variables and global variables, variables inside of functions, and variables outside of functions. One objective of good programming in C was in keeping the number of global variables to a minimum. Because any global variable could be modified by any function, it was easier to get the sense of a program if there simply weren’t very many of them — if functions communicated among themselves strictly through arguments and return values.

Sometimes, however, C programmers got a little, let’s say, sleepy, and made a lot of variables global that didn’t really need to be, because it was just easier that way. Rather than add an extra argument to a function, why not just store it as a global?

Global variables are basically gone in object-oriented programming, except that fields are now the new global variables, and they can be abused just as badly.

One basic principle of object-oriented programming is hiding data. This is generally meant to apply between classes. Classes shouldn’t expose everything they have. They should have as small a public interface as possible, and other classes should know only what they need to know. But the principle of data hiding is just as important inside a class. Methods should have limited access to the data that other methods are using. In general, variables should be made local to a method unless there’s a specific reason why they need to be accessed from some other method.

When you create an object using the new operator, the amount of storage allocated from the heap for the object must be sufficient to accommodate all the fields defined in the class you’re creating the object from and all the ancestor classes. The fields basically define the size of the object in memory. I know that we’re long past the point of worrying about every byte of storage, but when you look at the fields you’ve defined in your class, you should be asking yourself: Does all this stuff really need to be stored with each object in the heap? Or have I successfully restricted the fields to that information necessary to maintain the object?

Someone told me that he likes to store objects as fields because he’s afraid the .NET garbage collector will snag everything that’s not nailed down into a proper field definition. After years of defining very few fields in .NET, I can tell you this is not a problem. The .NET garbage collector will only delete objects that are no longer referenced anywhere in the program. If you can still access an object in some way, it is not eligible for garbage collection.

In theory, no child control created as part of a form needs to be stored as a field because the parent — generally a form — stores all its child controls in the collection named Controls, and you can reference each control by indexing the Controls property using and integer or the text Name property you assigned to it when creating the control. And here again you’re in much better shape if your controls have meaningful names and not button1, button2, button3, label1, label2, label3

Whether a particular object is defined as a field or a local variable is something that we as programmers should be thinking about with every object we create. A label that has the same text during the entire duration of the form can easily be local. For a label whose text is set from an event handler of some other control, it’s probably most convenient to store as a field.

It’s as simple as that. But Visual Studio doesn’t want you to think about that. Visual Studio wants everything stored as a field.

Visual Studio Demystified

Even if Visual Studio generated immaculate code, there would still be a problem. As Visual Studio is generating code, it is also erecting walls between that code and the programmer. Visual Studio is implying that this is the only way you can write a modern Windows or web program because there are certain aspects of modern programming that only it knows about. And Visual Studio adds to this impression by including boilerplate code that contains stuff that has never really been adequately discussed in the tutorials or documentation that Microsoft provides.

It becomes imperative to me, as a teacher of Windows Forms programming and Avalon programming, to deliberately go in the opposite direction. I feel I need to demystify what Visual Studio is doing and demonstrate how you can develop these applications by writing your own code, and even, if you want, compiling this code on the command line totally outside of Visual Studio.

In my Windows Forms books, I tell the reader not to choose Windows Application when starting a new Windows Forms project, but to choose the Empty Project option instead. The Empty Project doesn’t create anything except a project file. All references and all code has to be explicitly added.

Am I performing a service by showing programmers how to write code in a way that is diametrically opposed to the features built into the tool that they’re using? I don’t know. Maybe this is wrong, but I can’t see any alternative.

Dynamic Layout

I’ve been talking about the release of Visual Studio 2005 next month. Along with Visual Studio is also the .NET Framework 2.0, with some significant enhancements to Windows Forms, including a very strong commitment to “dynamic layout” (sometimes also known as “automatic layout”). Dynamic layout is also a significant part of the design philosophy of Avalon.

Dynamic layout is an example how Web standards have now influenced standalone client Windows programming. We have learned from HTML that it’s not necessary to put every single object on the screen with precise pixel coordinates. We have learned that it’s possible for a layout manager built into our browsers to flow text and graphics down the page, or to organize content in a table or frames. HTML has also provided a good case study in illustrating some ways not to implement these things, so these ways can be avoided.

Basically, when using dynamic layout in Windows Forms, the actual location and size of controls isn’t decided until run time. When the form is displayed, the layout manager takes into account the size of the controls, the size of the container, and lays out the controls appropriately.

Dynamic layout under Windows has come to be seen as necessary for a couple reasons. First, we are getting closer to a time when 200 dpi and 300 dpi displays will become available. It would be very nice if Windows programs written today didn’t crumble into incoherence on these displays.

Also, as controls have become more complex, they have become more difficult to use in predefined layouts. How big should a particular control be? Perhaps that can only be known at run time. It’s much better if the program does not impose a size on the control, but rather that the control determines its own size at run time, and to have that size taken into account during layout.

Now obviously this is more complex, because a layout manager has to interrogate the controls and determine how large they want to be, and then attempt to accommodate them all within an area of screen real estate.

But this is built into the classes of Windows Forms 2.0. The FlowLayoutPanel and the TableLayoutPanel together with the SplitContainer and the Dock property provide a full array of tools for dynamic layout. You can basically design entire forms and dialog boxes largely without using pixel coordinates or sizes. There are some exceptions, to be sure. You’ll probably want to set widths of combo boxes to specific sizes based on average character widths. But for the most part, this stuff works. In my new book I have a whole chapter on dynamic layout that concludes with code that duplicates the standard FontDialog with a TableLayoutPanel, and I come pretty close.

We now have the proper tools in the form of classes to render the Visual Studio forms designer obsolete. Unfortunately, nobody has told Visual Studio about this new age. Visual Studio definitely supports layout based on FlowLayoutPanel and TableLayoutPanel, of course, but you have to know about these things and explicitly put them on your form before you start populating the form with controls. Inexplicably, Visual Studio still stores pixel coordinates and sizes in your source code even though they are irrelevant in these cases

Avalon and XAML

Some people have assumed that with the planned introduction of Avalon next year — now properly called the Windows Presentation Foundation — that Windows Forms is already obsolete. But the more I look at Avalon, the less I believe that to be the case. Certainly Avalon has the power and breadth to support large applications, and a graphics system that will bring 3D capability to the average programmer.

But Avalon is currently missing some amenities we take for granted, such as standard File Open, File Close, and Font dialogs, a split panel, and it has nothing approaching the new and totally astonishing DataGridView control in Windows Forms 2.0. Whether these things get into Avalon before it’s released, I don’t know. But Windows Forms may still be the best bet for quickly constructing forms-based applications for in-house corporate use.

Avalon, as I mentioned, also has a strong commitment to dynamic layout. In Windows Forms, doing layout with pixels locations and sizes is basically the default. You need to specifically create a FlowLayoutPanel or TableLayoutPanel to dispense with pixels.

In Avalon, working with pixel coordinates is not the default. For each window or page, you have to pick a particular layout model, and the one where you specify pixels — a descendent of Panel named Canvas — is certainly being deemphasized as a choice. And even if you do go with Canvas, you’re not really working in units of pixels. You’re using something oddly called “device-independent pixels,” which is a coordinate system based on units of 1/96th of an inch, which is a one-to-one map with today’s default video display settings, but lets us achieve device independence with non-default settings.

But that’s not the half of it. When you put together your windows and dialogs in Avalon, you can do it either in code or in XML. Microsoft has come up with an entire page description language called XAML, the Extensible Application Markup Language, pronounced “zammel.” In a proper Avalon program, the XAML is supposed to contain all the layout stuff, and the programming code ties it all together, mostly with event handlers.

I was at first skeptical of this invention called XAML. I had liked the Windows Forms approach of doing everything in code, and now something like a resource script — but obviously much more sophisticated — was being reintroduced into Windows programming. I gradually became persuaded, however, and now I like it.

One thing that the Avalon architects are trying to do is let programmers and designers work around common files. Not every software project requires people who design the screens and dialog boxes, but large ones do, and in the past the designers did mockups with graphical tools and used bitmaps to show the programmers what they wanted. With Avalon they can use design tools that create and edit XAML, and the programmers can use this same XAML as source code in creating the executables.

Another reason I was persuaded in this: As we get more into dynamic layout, a form becomes a hierarchy of different types of panels and controls. You might start with a DockPanel and put menus and toolbars at the top of a window and a status bar at the bottom, and then inside you put a Grid panel, and then perhaps within some of the cells of the grid you have a StackPanel, and so forth.

This hierarchy of panels and controls has an analogue in the XAML as a nesting of elements. If the XAML is indented in a standard way, you can see the hierarchy right there in the file.

I also have much less of a problem with a visual designer generating XAML than generating C# code. As we’ve seen, Visual Studio doesn’t even want you to look at the C# code it generates, and for good reason. But XML is different. It was a design point of XML that it can be created and edited by either human or machine, and it shouldn’t matter at all which is which. As long as the XML is left in a syntactically and semantically correct state — and there is no middle ground — it shouldn’t matter who edits it and in what order. If I’m going to be putting XAML in a book, it doesn’t matter if I wrote it or Visual Studio wrote it, because it should basically be the same. And, for someone who wants to recreate the layout of panels and controls in Visual Studio, the XAML serves as a clear guide in illustrating the hierarchy.

Will there be a designer built into Visual Studio that works entirely with XAML and lets me write my own C# code? I don’t know yet. It certainly makes sense.

I am also hoping that developers eventually achieve a good balance between XAML and code. The Avalon architects are so proud of XAML — and rightfully so — that they tend to use it for everything. I saw an Avalon clock application that somebody at Microsoft wrote. It actually set the time once in code and used Avalon animation entirely implemented in XAML to keep the clock going. It was very, very cool, except that the 12 tick marks of the clock were implemented in 12 virtually identical chunks of XAML. The only thing that would have appalled me more was seeing 60 tick marks implemented 60 identical chunks of XAML.

I don’t know what rule you go by, but for me it’s always been simple: “Three or more: Use a for.” This is why we have loops. This is why we are programmers.

The Pure Pleasures of Pure Coding

A couple months ago — perhaps as an antidote to all this highfalutin Windows Forms and Avalon programming I’ve been doing — I started coding in C again. Just a little bit. A magazine I read — the British weekly New Scientist — runs a tiny regular feature called “Enigma,” which presents a little math puzzle. Here’s a particularly short one from this past June: “What is the largest integer whose digits are all different (and do not include 0) that is divisible by each of its individual digits?”8 If you solve one of the Enigma problems, you can send in your solution, and one is chosen at random on a particular date, and if yours is picked you get 15 pounds and a mention in the magazine.

These Enigma problems have actually annoyed me for years because they always seemed solvable by writing a short program and testing out the possibilities, and for some reason that seemed absurd to me.

A few months ago I decided it might actually be interesting solving the problems with code, and then posting the programs and solutions on my web site the day after the deadline, but about a week before the answer appears in print.

I decided to use plain old ANSI C, and to edit the source code in Notepad — which has no IntelliSense and no sense of any other kind — and to compile on the command line using both the Microsoft C compiler and the Gnu C compiler.

What’s appealing about this project is that I don’t have to look anything up. I’ve been coding in C for 20 years. It was my favorite language before C# came along. This stuff is just pure algorithmic coding with simple text output. It’s all content.

I also discovered is that the problems do require some thought before you code them up. Very often, the total number of combinations is prohibitive. You really have to whittle them down. You don’t want to write a program that runs for a week before getting to the printf statement. For example, take the problem I quoted: “What is the largest integer whose digits are all different (and do not include 0) that is divisible by each of its individual digits?” It really helps to realize that this integer cannot contain the digit 5 if it also contains any even digit, because then the number would be divisible by 10, and the last digit would be 0, which isn’t allowed. So, the number we’re looking for probably doesn’t include 5. That immediately reduces the possibilities by an order of magnitude.

Even after this preliminary process, there’s still coding to do, but there’s no APIs, there’s no classes, there’s no properties, there’s no forms, there’s no controls, there’s no event handlers, and there’s definitely no Visual Studio.

It’s just me and the code, and for awhile, I feel like a real programmer again.


1It was the late 70s. I was working for New York Life Insurance Company at 51 Madison Avenue, programming in PL/I on an IBM 370 via TSO (Time Sharing Option) and an IBM 3278 terminal. I was using a new-fangled "full-screen editor" called FSE to edit my source code. At one point I pressed the Backspace key and instead of the cursor moving backwards as is normal, the entire screen moved left one character, including the frame of the editor, with the beginning of each line wrapping to the end of the preceding line. It was as if the entire frame buffer shifted. I pressed the Backspace key a couple more times, and it did the same thing. Then it started going by itself, with the lines circling around the screen and right up through the top until the screen was entirely clear. Then we called the IBM repair guy. I was very eager to tell him what happened and hear his diagnosis, but that's not how they repaired 3278s. Instead, the repair guy had a box full of spare circuit boards. He swapped them in and out of the machine until the terminal worked again.

2Others can be found on the page “Hollywood & Computer” from the Charles Babbage Institute web site: http://www.cbi.umn.edu/resources/hollywood.html.

3“Taglines for Colossus: The Forbin Project,” http://www.imdb.com/title/tt0064177/taglines.

4“Focus: Misguided Missiles,” The Onion (New York City print edition), vol. 41, no. 30, pg. 15.

5Manually counted in “Quick Reference” section of Microsoft Windows Software Development Kit: Programmer’s Reference (Microsoft Corporation, 1985).

6Charles Petzold, Programming Windows 95 (Microsoft Press, 1996), pg. 17.

7A package of 500 Staples brand cards is approximately 4 inches.

8“Enigma 1343: Digital Dividend,” New Scientist, 4 June 2005, 28.


© 2005, Charles Petzold (www.charlespetzold.com)
First Posted: October 2005


Back to the Et cetera page.

Back to Home

mindware 发表于 2006-2-27 15:46:00


处理 SSI 文件时出错

发表评论:

    昵称:
    密码: (游客无须输入密码)
    主页:
    标题:
    页面数据载入

 
? COPYRIGHT 2001 ALL RIGHTS RESERVED http://www.blog.edu.cn
处理 SSI 文件时出错