
- •Table of Contents
- •About the Author
- •Acknowledgments
- •Introduction
- •Version Support
- •Supported Versions
- •A Unified Platform
- •Roadmap
- •Supported Operating Systems
- •Command Line Interface
- •Desktop Development
- •Blazor
- •MAUI
- •Wrapping Up
- •.NET 6 Architecture
- •Runtimes
- •CoreCLR
- •Mono
- •WinRT
- •Managed Execution Process
- •Desktop Packs
- •Wrapping Up
- •Dotnet New
- •Dotnet Restore
- •NuGet.config
- •Dotnet Build
- •Dotnet Publish
- •Dotnet Run
- •Dotnet Test
- •Using the CLI in GitHub Actions
- •Other Commands
- •Wrapping Up
- •WinAPI
- •WinForms
- •STAThread
- •WinForms Startup
- •DPI Mode
- •Responding to Scale Events
- •Visual Styles
- •Text Rendering
- •The Message Loop
- •The Form Designer
- •WPF Startup
- •XAML Layout
- •Visual Tree
- •Data Binding
- •Windows App SDK
- •Building a Windows App SDK application
- •Using Windows APIs with Windows App SDK
- •Packaging
- •Migrating to .NET 6
- •Upgrade Assistant
- •Wrapping Up
- •Blazor WebAssembly
- •Creating a Blazor Wasm Project
- •Blazor Progressive Web Apps
- •Exploring the Blazor Client Project
- •Blazor in .NET 6
- •Blazor Component System
- •Creating Blazor Pages
- •Running a Blazor App
- •Blazor Server
- •SignalR
- •Blazor Desktop
- •Wrapping Up
- •Project Structure
- •Exploring MAUI
- •The Cross-Platform World
- •Application Lifecycle
- •MVVM
- •MVVM Toolkit
- •Wrapping Up
- •Model-View-Controller
- •Routing
- •Views
- •Controllers
- •Controller-Based APIs
- •Minimal APIs
- •Wrapping Up
- •Web Apps
- •Creating an App Service
- •Static Web Apps
- •Web App for Containers
- •Docker
- •Azure Functions
- •Deploying Azure Functions
- •Wrapping Up
- •Record Types
- •Monolith Architecture
- •Microservices
- •Container Orchestration
- •Kubernetes
- •Docker Compose
- •Dapr
- •Installing Dapr
- •Dapr State Management
- •Wrapping Up
- •Roslyn
- •Compiler API
- •Diagnostic API
- •Scripting API
- •Workspace API
- •Syntax Tree
- •Roslyn SDK
- •Source Generators
- •Writing a Source Generator
- •Debugging Source Generators
- •Wrapping Up
- •Garbage Collector
- •The Heap
- •The Stack
- •Garbage Collection
- •A Look at the Threadpool
- •Async in .NET 6
- •Await/Async
- •Cancellations
- •WaitAsync
- •Conclusion
- •Index
Chapter 4 Desktop Development
WinForms
WinForms was introduced in 2002 as part of the initial release of .NET. It was meant to be the successor of the very popular Visual Basic 6. WinForms provided the same graphical editor that allowed developers to drag and drop a user interface onto a canvas, specifying anchor points to specify resizing behavior.
WinForms is a managed wrapper around Win32, enabling .NET as an option to create Windows applications.
Within Win32 is an API set responsible for drawing 2D vector graphics and formatted text on the screen; this API is called GDI+ (or simply GDI on Windows versions older than Windows XP). GDI+ stands for Graphics Device Interface. It is an abstraction
layer between applications and the graphics hardware. WinForms relies heavily on GDI+ to perform its rendering. As .NET developers, we usually don’t come into direct contact with GDI+; instead, we use the abstractions provided by WinForms and let the framework handle all the low-level drawing code. Before .NET 6, WinForms was strictly using GDI+ for drawing on the screen, which made development easier as it creates an abstraction of the graphical device; while this made development easier, it also slowed down performance because of the abstraction overhead. To solve this, the WinForms team opted to use the classic GDI in specific cases, for example, when rendering brushes.
Let’s explore WinForms. From Visual Studio 2022, start a new project and select WinForms as project template. Give it a good name and let the project generate. Building a user interface in WinForms is usually done through the designer surface in Visual Studio; the designer generates C# code that is used to actually draw all elements on screen. We can write the C# directly should we need to, but the designer greatly simplifies creating complex screens. To open the designer, double-click Form1.cs in the solution explorer.
69

Chapter 4 Desktop Development
Figure 4-1. The WinForms designer
Figure 4-2 shows the basic layout of a new WinForms project in .NET 6.
Figure 4-2. A new .NET 6 WinForms project
In the Frameworks section, you’ll notice an entry for .NET, Microsoft.NETCore.App, and another reference called Microsoft.WindowsDesktop.App.WindowsForms. This is the desktop pack needed to be able to run and develop Windows native desktop applications with .NET 6. More information on extensibility packs can be found in Chapter 2 of this book. Program.cs contains the entry point of our application. Listing 4-2 shows the default Program class.
70
Chapter 4 Desktop Development
Listing 4-2. Default Program class
internal static class Program
{
///<summary>
///The main entry point for the application.
///</summary>
[STAThread] static void Main()
{
ApplicationConfiguration.Initialize(); Application.Run(new Form1());
}
}
Program is a static class; just like any other .NET 6 project, it is the starting point of our application.
STAThread
First thing to note here is the STAThread attribute. STA stands for single-threaded apartment; to understand what this does, we need to make a sidestep into the world of the apartment model process, but before we get into that we need to make sure we’ve got the meaning of a few concepts right.
Process: A set of resources, code, data, and virtual memory
Thread: Code that is executed within a process in a linear way
An application typically has one process that can contain one or more threads. Creating multiple threads within a process allows our application to execute code in parallel; do keep in mind that running code in parallel does not automatically guarantee an increase in performance. Multithreading can be hard to get right and comes with its own set of challenges like thread safety, preventing deadlocks and race conditions.
Component Object Model, or COM, enables application to open up their functionality to other applications in an API-like manner, by generating wrappers that can be called in other application. Windows exposes COM wrappers, for example, for the file and folder dialogs or message boxes.
71