Programming Windows: Hello, .NET Framework and Windows Forms (Premium)

While most of Microsoft’s public .NET pronouncements involved web services, .NET also brought a major upgrade to Windows app development: the .NET Framework and its Windows Forms class libraries and Visual Studio.NET integration. Here, we’ll examine some of those advances.

As you may recall, the Windows API (Win32) was a flat, unorganized collection of many thousands of confusing C-based functions. But the .NET Framework was—and still is—an object-oriented and organized hierarchical class library consisting of logical containers called namespaces. A namespace can contain other namespaces, classes representing various objects, most of which are further sub-classed to create more specific objects, and other items. Each object provides a variety of fields, properties, and methods for developers to access.

The .NET Framework’s hierarchical nature solved many of the problems with Win32, key among them that Win32’s flat, disorganized nature meant that every function name in the Windows API had to be unique. But once you move to a hierarchical system, that limitation disappears. Indeed, you will see the same method names in various classes throughout the .NET Framework. Every interactive control, for example, has a Click() method. What makes each unique is their fully qualified name, which includes their containing namespaces and classes.

The .NET Framework also solved some of the technical limitations of classic Visual Basic, which was object-based and not object-oriented. This is not a semantical distinction. In a truly object-oriented system like the .NET Framework, subclasses inherit the capabilities of the classes from which they derive, and they evolve those capabilities as needed. A low-level class like Control provides basic features, but control subclasses that derive from it—Button, TextBox, and so on—provide more specific functionality.

That’s just the beginning of the benefits of .NET, which also provides memory management, garbage collection, structured exception handling, simpler ways to access and interoperate with COM/DCOM/COM+, and other important features. But let’s stick with the .NET Framework and how it impacted Windows app development.

The topmost class in the .NET Framework is called, appropriately enough, System. Below System are various other namespaces, including Media, Security, Text, Timing, and others. System also has classes of its own, including the Console class that is used to create console (command line) applications. Console, in turn, has events, properties, and methods. We use Console methods like Write() and WriteLine() to write text to the console window, and methods like Read(), ReadKey(), and ReadLine() to read input from the user.

Looked at another way, the console’s Write() method has a fully qualified name of System.Console.Write(). But in C#, we use the using keyword to import a namespace like System into a code project so that we don’t need to be so verbose.

A complete command-line application that writes a greeting to the console could look like so:

using System;

namespace ConsoleApp1
{
    internal class Program
    {
        static void Main(string[] args)
        {
            Console.Write("Hello, .NET Framework!");
        }
    }
}

Since this came up recently in an embarrassing Microsoft tweet, consider the .NET Framework’s DateTime class, which also resides in the System namespace. Popular properties include Now and Today, while commonly needed methods include Compare(), DaysInMonth(), and IsLeapYear(). Thinking about Microsoft’s recent coding mistake, one might check to see whether today is New Years Day and then write an appropriate message like so.

DateTime dt = DateTime.Today;
    if (dt.Month == 1 & dt.Day == 1)
        Console.WriteLine("Happy New Year!");
    else
        Console.WriteLine("Sorry, it's not New Year’s.");

This is only one possible solution, and it doesn’t completely address the mistakes in that tweet. But the idea here is that we’re checking to see whether it’s January 1st, which is month 1 and day 1. If it is, we display a “Happy New Year!” message. If it isn’t, we display a different message.

Windows Forms

The .NET Framework also allowed developers to create graphical Windows applications and interact with the system in ways that were far easier—but in most ways no less powerful—than using the Windows API (Win32). This occurred through Windows Forms, which can be found in the System.Windows.Forms namespace. And still does, since Windows Forms is an ongoing concern over 20 years later. So I’ll switch to the present tense again.

Here’s a simple example: Using Windows Forms, you can access the contents of the Windows Clipboard via the System.Windows.Forms.Clipboard class, logically enough. This class provides several methods, among them GetText(), GetData(), Clear(), SetText(), and SetData().

You might apply the Clipboard text to the current form’s title bar with the following lines of code:

if (System.Windows.Forms.Clipboard.ContainsText())
    Text = System.Windows.Forms.Clipboard.GetText();
else
    Text = "There is no text in the Clipboard.";

And if you first copy the text “Hello, world!” to the Clipboard using Notepad and then run the application, this text will appear as expected in its title bar.

As with classic Visual Basic, developers create a blank Windows Forms application that provides a blank form representing the main application window, though this work now occurs in Visual Studio and usually involves C#, not Visual Basic. Then, they can easily build the application’s user interface visually, using a rich toolbox full of controls, including all the obvious choices—Button, CheckBox, Label, MenuStrip, TextBox, and so on—plus a nice collection of system dialogs like FontDialog, OpenFileDialog, PrintDialog, SaveFileDialog, and others, and more.

But Windows Forms is also more sophisticated than its predecessor, and not just at the language level. One of the problems with classic VB was that it was difficult to automatically layout the controls on a form when the user resized the window. With Windows Forms, that is no longer the case: developers could now access the Anchor and Docking properties of each control to determine how they were positioned and size relative to their parent control/container. In that way, Windows Forms apps introduced Microsoft’s first implementation of automatic layout for Windows app developers.

For example, I used the Dock property in the Windows Form version of .NETpad to ensure that its textbox always fills the entire available application surface (minus the menu bar at the top and the status bar at the bottom) by setting it to Fill, which of type DockStyle.

Using another simple example, the button in the lower right corner of this application will always maintain the same distances from the lower right corner of the application window that contains it, no matter how the window is resized.

These and other properties can be set visually by selecting a control and accessing its list of properties in the Properties window in Visual Studio. Or they can be applied via code, of course.

button1.Anchor = AnchorStyles.Right | AnchorStyles.Bottom;

But one of the things that has always impressed me about both classic VB and Windows Forms is how much of an application one can create without writing a single line of code. (In fact, this was one of my proof points when I started the first version of .NETpad.) Once you understand how the designers work, it’s easy to build an application’s entire user interface, no matter the complexity, visually. Then, you can simply wire up the necessary event handlers just as easily.

For example, if you want to handle that button’s Click() event, which fires when the user clicks it, you can just double-click it in the designer, and Visual Studio will switch to the underlying C# (or VB.NET) code file and create an empty event handler for you:

private void button1_Click(object sender, EventArgs e)
{  

}

That works because Click() is that control’s default event handler. But you can also create this and other event handlers by selecting a control in the designer and then switching the Properties window to an Events window by selecting the Events (lightning bolt) toggle. Then, a list of available events will appear; just double-click one to add an empty event handler to the code.

Language interoperability

Before moving on, let’s quickly examine how the .NET Framework’s language independence works. That is, it’s possible to write some code in one .NET language, like Visual Basic, and other code in another, like C#. And those codebases can easily interact in many different ways.

Here’s a very simple example.

Using Visual Basic, I created a Windows DLL using Visual Studio’s Class Library (.NET Framework) project in Visual Basic. The project provides a single class, Hello, which has a single function, SayHello(), that returns a familiar hard-coded string.

Public Class Hello
    Public Function SayHello() As String
        Return "Hello, .NET Framework!"
    End Function
End Class

After saving and building that project, I created a Windows Forms application using C# and the .NET Framework. This application has a single control, a button.

Before adding the button’s Click() event handler, I used the Visual Studio Resource Manager (Project > Add Resource) to find the DLL file I had created. This added the line “using HelloVB” to the form’s source code:

Then, I added the button’s Click() event handler and wrote some simple code to display a message box that outputs the string returned by the Hello class’ SayHello() function like so:

private void button1_Click(object sender, EventArgs e)
{
    Hello hello = new Hello();
    MessageBox.Show(hello.SayHello());
}

And there you go: though the DLL was written in Visual Basic and the Windows Forms application was written in C#, the two can interact seamlessly. We created an instance of the Hello object, which was created with Visual Basic and is stored in a DLL, and we called its SayHello() method using its fully-qualified name.

If you’re an experienced .NET developer shaking your head at this borderline silly example, I apologize. But it does demonstrate the power of .NET, in that developers can create code in the language of their choice and interoperate seamlessly in the .NET environment. And while I’m focusing on Windows in this series, one might also write components or other code that exists on an Internet-facing Windows Server and access it using ASP+ (later renamed ASP.NET) and Web Forms on another system and display a similar greeting to a user accessing a web page. Pretty cool.

Gain unlimited access to Premium articles.

With technology shaping our everyday lives, how could we not dig deeper?

Thurrott Premium delivers an honest and thorough perspective about the technologies we use and rely on everyday. Discover deeper content as a Premium member.

Tagged with

Share post

Thurrott