Browse DevX
Sign up for e-mail newsletters from DevX


.NET Building Blocks: Custom User Control Fundamentals : Page 2

Find out the gritty details required to create, test, use, inherit, install, and distribute .NET User Controls of all types.




Building the Right Environment to Support AI, Machine Learning and Deep Learning

Creating an Inherited User Control
Standard .NET controls and components are building blocks that you use to create applications or other building blocks. In the previous section, you created a new building block called ClockControl. In this section, you will build yet another building block, based on the ClockControl. Add a new item to your project and the Add New Item dialog opens, as in Figure 3. Select the "Inherited User Control" template and name it "AlarmClockControl."

Figure 3. Creating an Inherited Control: When you create an Inherited User Control project, you'll get a second dialog where you select the control from which to inherit.

Figure 4. Impact of a Completed Control: When you create the AlarmClockControl inherited user control, Visual Studio adds the already-completed ClockControl to the Toolbox automatically, and you can see its inherited, exposed properties in the Properties window.
Upon pressing Add, you will get an additional dialog box that is specific to inherited controls. This dialog asks you what control you wish to inherit from. By default, it lists all the controls in the current project. In this case, you have only one so far, the ClockControl; choose that one.

When you complete the dialog, the user control designer opens the new AlarmClockControl. On the left, in the Toolbox, you have a new category of ControlLib components listing the one and only control you have added so far, ClockControl (see Figure 4). So just like a Button or a Label, you could drag a ClockControl onto the designer surface to add it to your application or to build another composite control. Because you're building an inherited control—inheriting from the ClockControl—you need do nothing further. Over on the right side, you'll see the familiar exposed properties, shown in the Misc category here in the designer just as they were in the UserControl Test Container.

When the designer opens, it automatically selects the entire user control, so you'll see the properties of the control itself in the Properties window. However, for an inherited user control the designer lets you explore the hierarchy of your control simply by clicking internal components. For example, click on the clock display and the clockLabel becomes the selected component. You can then see its properties in the Properties window, albeit as read-only (see Figure 5).

Figure 5. Inherited User Control Internals: Visual Studio lets you see (but not modify) properties of child controls in the parent object by selecting them.

Continuing in parallel with Microsoft's walkthrough, switch to the code view and add an AlarmTime property of type DateTime and a Boolean AlarmSet property. The default generated code with the added properties is shown below:

namespace ControlLib { public partial class AlarmClockControl : ControlLib.ClockControl { public DateTime AlarmTime { get; set; } public bool AlarmSet { get; set; } public AlarmClockControl() { InitializeComponent(); } } }

The preceding code sample takes advantage of a new feature in C# 3.0 called auto-implemented properties. (See what's new in C# 3.0 here.) For a property that follows the standard pattern of a backing variable, a setter that assigns to the backing variable, and a getter that retrieves from it, you can now use a much shorter notation: no backing variable declaration and no bodies for the getter and setter, as shown for AlarmTime and AlarmSet. If you are using Visual Studio 2005 or C# 2.0, you will need to use the more verbose forms for the getter and setter accessors.

After declaring the two properties, go back to the designer and add both a label (named AlarmLabel) and a button (named alarmOffButton). Finally, you need to override the base ClockControl timer's Tick event handler to flash an alarm at the set time, and you'll need to add an event handler for the new Button's Click event. The complete code sample is shown next with the new portions in bold:

namespace ControlLib { public partial class AlarmClockControl : ControlLib.ClockControl { public DateTime AlarmTime { get; set; } public bool AlarmSet { get; set; } private bool colorTicker; public AlarmClockControl() { InitializeComponent(); } protected override void timer1_Tick( object sender, System.EventArgs e) { base.timer1_Tick(sender, e); if (AlarmSet) { if (AlarmTime.Date == DateTime.Now.Date && AlarmTime.Hour == DateTime.Now.Hour && AlarmTime.Minute == DateTime.Now.Minute) { // If the date, hour, and minute // of the alarm time are the same // as the current time, flash an alarm. alarmLabel.Visible = true; alarmLabel.BackColor = colorTicker ? Color.Blue : Color.Red; colorTicker = !colorTicker; } else { // After the alarm has sounded for a minute, // hide it again. alarmLabel.Visible = false; } } } private void alarmOffButton_Click(object sender, EventArgs e) { AlarmSet = false; alarmLabel.Visible = false; } } }

Figure 6. Executing the AlarmClockControl: The test container shows the alarm going off when the current time reaches the set time (the value of the AlarmTime property).
To test the AlarmClockControl, press F5 and the test container opens (see Figure 6). Typically, you'd set the AlarmTime and AlarmSet properties in code, but to test the alarm, set the properties manually in the test container window. Select the AlarmTime property and set it a minute or two ahead of the current time. Change the AlarmSet property to True to activate the alarm clock. At the designated time the alarm will begin to flash. Press the Disable Alarm button to deactivate it.

Using the AlarmClockControl
To complete the real-world process of building a user control, the final step is to include the AlarmClockControl in an application. Create a new Windows Forms Application project in the same solution called TestAlarmClock. Visual Studio opens the designer with a blank form and (because the new project exists in the same solution as the user controls) automatically populates the Toolbox with the ClockControl and the AlarmClockControl controls (see Figure 7).

Figure 7. Auto-Populating the Toolbox: A new project in a solution automatically includes available controls from other projects in that solution in the Toolbox under ControlLib Components.

Drag an AlarmClockControl and a standard DateTimePicker control onto the designer surface. To wire these up, you'll need an event handler for the DateTimePicker. Double-click the DateTimePicker to create an event handler for its default ValueChanged event. Enter the two lines of code highlighted below into the event handler method. Note that these two lines of code do programmatically precisely what you did manually in the UserControl Test Container in the previous section. Here's the entire program (not counting the designer-generated code):

namespace TestAlarmClock { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void dateTimePicker1_ValueChanged( object sender, EventArgs e) { alarmClockControl1.AlarmTime = dateTimePicker1.Value; alarmClockControl1.AlarmSet = true; } } }

Figure 8. The TestAlarmClock Application: The completed application UI is on the left; an exploded view, showing the nested components is on the right.
When you execute the program, you turn on the AlarmClockControl just by entering an alarm time value. (Note: Don't open the calendar in the DatePicker; just select one component of the time and type in a new value.) You disable the alarm by pressing the Disable Alarm button. Figure 8 shows the completed application UI in two different forms. The flat form at left shows what you see in the visual designer. The exploded form at right illustrates the hierarchical components that you have just assembled:

  • The form contains a DateTimePicker and an AlarmClockControl.
  • The AlarmClockControl contains a Button and (by inheritance) a ClockControl.
  • The ClockControl contains a Label and a (non-visible) Timer.
Figure 8 provides a visual aid to understanding what properties are accessible where. At any given level, you can access exposed properties only for those controls and components that are immediate children or inherited controls. In other words, from the form level, you can set public properties of both the DateTimePicker and AlarmClockControl. The AlarmClockControl defines AlarmTime and AlarmSet properties, but because it inherits from ClockControl, you also have access to ClockControl's public properties: ClockForeColor and ClockBackColor.

Thanks for your registration, follow us on our social networks to keep up-to-date