.NET Application Development
- Developing Components
- Developing Controls
- Resources and Internationalization
- Summary
In this chapter I want to discuss the issues that will arise when you come to develop applications. A .NET application that lacks a user interface typically is made up of components, and UI applications consist of forms that have components and controls. Visual Studio.NET has been designed to make developing applications simple and to aid rapid application development (RAD) by allowing you to generate code simply by dragging and dropping components.
I will start by explaining what constitutes a component and what extra facility you get with controls. I will then show you how to develop a control that will integrate with the IDE's Toolbox and Properties windows, and how you can make it easier for the users of your controls to change their properties.
The world we live in moves day by day to a single global market, so it is extremely important that your application, components, and controls not be tied to a single locale. Internationalization in .NET is carried out with locale-specific resources. The VS.NET IDE has been designed to make the internationalizing process as simple as possible, and I'll show you how this works and how the localized resources are deployed. .NET resources are handled differently from Win32 resources, so I will show you how to create resources and how to include Win32 resources in your assemblies when .NET resources are deficient.
8.1 Developing Components
I mentioned in Chapter 6 that components are items that implement ICompo-nent. This interface derives from IDisposable, which means that components allow explicit management of their resources, and will inform interested classes when they are disposed of. In addition, the IComponent interface has a Site property that is initialized to the site of a container:
// C# public interface IComponent : IDisposable { ISite Site { get; set; } event EventHandler Disposed; // IDisposable members void Dispose(); }
A container implements the IContainer interface:
// C# public interface IContainer : IDisposable { ComponentCollection Components { get; } void Add(IComponent component); void Add(IComponent component, String string); void Remove(IComponent component); // IDisposable members void Dispose(); }
As the name suggests, the ComponentCollection class is an enumerable collection. The Add() and Remove() methods allow you to add components to this collection and remove them. The fact that IContainer derives from IDisposable is important because containers are used to hold resources (the components), so when an object that uses components is disposed of, the components should be disposed of too, through the implementation of IContainer.Dispose().
When you create a Windows Forms application you'll find that a container is created for you, as in this example:
// C# public class MyForm : System.Windows.Forms.Form { private System.ComponentModel.Container components = null; public MyForm() { InitializeComponent(); } protected override void Dispose(bool disposing) { if (disposing) { if (components != null) components.Dispose(); } base.Dispose( disposing ); } private void InitializeComponent() { this.components = new System.ComponentModel.Container(); this.Size = new System.Drawing.Size(300,300); this.Text = "My Form"; } }
The container member is not required. Indeed, if you write forms code by hand (e.g., in C++), you can dispense with the container member as long as you call Dispose() on each component.
The VS.NET Toolbox window contains a tab with standard components: classes for the event log, MSMQ queues, performance counters, and of course the timer component. These components lack a user interface, but you can still drag and drop them onto a form in the Windows Forms designer, which will generate code to add the component to the form class and will display that you are using the component by showing an icon at the bottom of the Designer window. You can access a component's properties by selecting the component in the Designer window and then switching to the Properties window.
Creating components is relatively straightforward. Your component, of course, must derive from IComponent, and the best way to do this is to derive from Component. The component will most likely be used as an item in the Toolbox window, so it will need a Toolbox image (which I'll explain later).
When you drag a component from the Toolbox window and drop it on a form in the Designer window, you are actually creating an instance of the component. It is important therefore that the component does not rely on constructor parameters; instead, your component should be initialized through properties. For example, look at how the System.Timers.Timer component is used:
When you drag and drop a timer onto a form, the generated code will create the component using its default constructor, and the interval of the timer is initialized through the Interval property, even though the Timer class has a constructor that takes an interval parameter.
Some componentsfor example, EventLog and MessageQueueallow you to access resources. Such components are great examples of components because they consist of code that GUI applications will use, but they themselves do not have a UI. Your components are likely to give access to similar resources.