14.14. User-Defined ControlsThe .NET Framework allows you to create custom controls. These custom controls appear in the user's Toolbox and can be added to Forms, Panels or GroupBoxes in the same way that we add Buttons, Labels and other predefined controls. The simplest way to create a custom control is to derive a class from an existing control, such as a Label. This is useful if you want to add functionality to an existing control rather than reimplement the existing control to include the desired functionality. For example, you can create a new type of Label that behaves like a normal Label but has a different appearance. You accomplish this by inheriting from class Label and overriding method OnPaint. All controls contain method OnPaint, which the system calls when a component must be redrawn (such as when the component is resized). Method OnPaint is passed a PaintEventArgs object, which contains graphics informationproperty Graphics is the graphics object used to draw, and property ClipRectangle defines the rectangular boundary of the control. Whenever the system raises the Paint event, polymorphism enables the system to call the new control's OnPaint. The base class's OnPaint method is not called, so you must call it explicitly from the derived class's OnPaint implementation before performing any customized painting operation. In most cases, you want to do this to ensure that the original painting code executes in addition to the code you define in the custom control's class, so that the control will be displayed correctly. To create a new control that is composed of existing controls, use class UserControl. Controls added to a custom control are called constituent controls. For example, you could create a UserControl composed of a Button, a Label and a TextBox, each associated with some functionality (for example, the Button might set the Label's text to the text contained in the TextBox). The UserControl acts as a container for the controls added to it. The UserControl contains constituent controls but does not determine how these constituent controls are displayed. Method OnPaint of the UserControl cannot be overridden. To control the appearance of each constituent control, you must handle each control's Paint event. The Paint event handler is passed a PaintEventArgs object, which can be used to draw graphics (lines, rectangles, etc.) on the constituent controls. Using another technique, you can create a brand new control by inheriting from class Control. This class does not define any specific behavior; that task is left to you. Instead, class Control handles the items associated with all controls, such as events and sizing handles. Method OnPaint should contain a call to the base class's OnPaint method. Inside the overridden OnPaint method, you can add code that draws custom graphics when drawing the control. This technique allows for the greatest flexibility, but also requires the most planning. All three approaches are summarized in Fig. 14.48.
We create a "clock" control in Fig. 14.49. This is a UserControl composed of a Label and a Timer whenever the Timer raises an event (once per second in this example), the Timer's event handler updates the Label to reflect the current time. Figure 14.49. UserControl-defined clock.
Timers (System.Windows.Forms namespace) are invisible components that reside on a Form, generating Tick events at set intervals. The interval is set by the Timer's Interval property, which defines the number of milliseconds (thousandths of a second) between events. By default, timers are disabled and do not generate events. This application contains a user control (ClockUserControl) and a Form that displays the user control. We begin by creating a Windows application. Next, we create a UserControl class for the project by selecting Project > Add User Control.... This displays a dialog from which we can select the type of control to addUser Control is already selected. We then name the file (and the class) ClockUserControl. Our empty ClockUserControl is displayed as a gray rectangle. You can treat this control like a Windows Form, meaning that you can add controls using the ToolBox and set properties using the Properties window. However, rather than creating an application's Form, you are simply creating a new control composed of other controls. Add a Label (lblDisplay) and a Timer (tmrClock) to the UserControl. Set the Timer's Interval property to 1000 milliseconds and set lblDisplay's text with each event (lines 59). To generate events, tmrClock must be enabled by setting property Enabled to true in the Properties window. Line 8 sets lblDisplay's text to the current time. Structure DateTime (namespace System ) contains property Now, which is the current time. Method ToLongTimeString converts Now to a String containing the current hour, minute and second followed by AM or PM. Once you build the project containing the custom user control, the control is automatically added to the IDE's Toolbox. You may need to switch to the application's Form in the Designer before the custom user control appears in the Toolbox. To use the custom control, simply drag it onto the Form and run the Windows application. We gave the ClockUserControl object a white background to make it stand out in the Form. Figure 14.49 shows the output of FrmUserControlTest, which contains our ClockUserControl. There are no event handlers in FrmUserControlTest, so we show only the code for ClockUserControl. Sharing Custom Controls with Other DevelopersVisual Studio allows you to share custom controls with other developers. To create a UserControl that can be exported to other solutions, do the following:
|