Introduction
Ever wanted to create a control like ErrorProvider
that sits in the non-UI portion of the UI designer and does stuff? It's fairly easy. I'll show an example here of how to derive from Component
and another helpful interface, ISupportInitialize
.
Component
The reason ErrorProvider
sits in the non-UI part of the designer is because it is a Component
. A Component
is the base class for all MarshalByRefObject
s in the CLR. Other things that derive from Component
are ToolTip
, Control
, HelpProvider
, ImageList
, and Menu
.
The Component
also exposes the site to a container and allows them to communicate. A Component
can be placed "in any object that implements the IContainer
interface, and can query and get services from its container".
Let's say, I wanted to write a component that would sit in the non-UI part of the designer (does anyone know what the heck that's called?) and after all the initialization is complete at run-time, it would fix the tab ordering automatically. Now, here the tab ordering algorithm is trivial, so let's assume it works. (Thanks to Scott McMaster, who wrote this article and was the inspiration for this article. Sorry about hacking up your TabOrderManager
so bad.)
using System;
using System.Collections;
using System.Diagnostics;
using System.Windows.Forms;
using System.ComponentModel;
using System.Collections.Specialized;
namespace ComponentTest
{
public class TabOrderManager : Component, ISupportInitialize
{
public void SetTabOrder()
{
...
}
public void BeginInit()
{
}
public void EndInit()
{
this.SetTabOrder();
}
}
}
Once you slap this on your form (and assign your form to the ContainerControl
property), you should notice that something funny has happened in InitializeComponent()
:
private void InitializeComponent()
{
this.tabOrderManager = new ComponentTest.TabOrderManager();
...
((System.ComponentModel.ISupportInitialize)(this.tabOrderManager)).BeginInit();
this.SuspendLayout();
...
this.Controls.Add(...);
((System.ComponentModel.ISupportInitialize)(this.tabOrderManager)).EndInit();
this.ResumeLayout(false);
}
ISupportInitialize
adds these things in InitializeComponent
automatically. Normally, they are for transacted notification of when batch initialization has started and finished. Now, when the TabOrderManager.EndInit()
is called, it sets the tab index of all the components on the form.