** 用 Visual C# .NET ** ** 开发简单的复合控件 **
** 内容提要: ** 本文介绍如何用 Visual C# .NET 2002 开发简单的复合控件 (Composite Control) ,主要讲解控件开发过程中的属性 (Property) 和事件 (Event) 处理,以方便开发人员在 .NET 平台下根据自己的需要开发适合的控件。
当我们在 .NET 平台下做 Windows Forms 开发时,常常需要为了某一特殊用途而把现有控件结合起来使用,比如结合了 Label 和 TextBox 的控件就非常容易在窗体上布局 ( 记得 Delphi 6 里就有这么个控件 ) ,而结合了特定图案和文字的控件则非常适合显示公司的 logo 。 .NET 平台就为我们提供了非常棒的工具和技术来创建这样的自定义控件。下面让我们来一起创作一个可以自动显示时间的控件。
值得注意的是, .NET 平台为我们提供了三种控件的开发技术,分别是:继承控件 (Extended Control) 、复合控件 (Composite Control) 和自定义控件 (Custom Control)( 译名可能会有所不同,大家可以以英文为准 ) 。我们现在关心的是第二种——复合控件。 OK , Let’s go!
** 1 ** ** .创建控件工程。 ** 在 Visual C# .NET 中新建一个“ Windows 控件库”项目,命名为“ TimeLabel ”,如图 1 :

** 2 ** ** .更改命名空间、控件类名称。 ** 默认的命名空间是 TimeLabel (和项目名称一样),控件类名称是 UserControl1 。请把命名空间改为与你的开发习惯一致,如我的是 LeoYang.Controls.TimeLabel ,当然你也可以选择保留默认命名空间;最好把控件类名称改为有意义的命名,如 TimeLabel ,这样当该控件出现在工具箱上时,就会显示为 TimeLabel 而不是 UserControl1 了。注意,一旦改动类名,则相应的 Construction 方法名称也要相应改掉,如:
public UserControl1()
{
…
}
就要改为:
public TimeLabel()
{
…
}
** 3 ** ** .添加现有控件。 ** 由于我们是要在现有控件的基础上创建新控件,所以就应该先把可用的现有控件添加到控件设计界面上。请在“工具箱”中双击 Label ,再双击 Timer ,两个现有控件依次被添加到我们的设计界面上,如图 2 :
** 4 ** ** .公布控件属性。 ** 因为要把时间写入 Label 的 Text 属性中,所以我们需要把 label1.Text 属性公开。请在 TimeLabel 类中加入以下代码:
public string LabelText
{
get
{
return label1.Text;
}
}
注意,这里我们不需要让控件使用者改变 label1.Text 的值,所以 LabelText 是个只读属性。
另外,出于美观的考虑,我们这里还要向控件使用者公开一个 LabelBackColor 属性,用于获得和设置 Label 的 BackColor 属性。代码如下:
public Color LabelBackColor
{
get
{
return label1.BackColor;
}
set
{
label1.BackColor=value;
}
}
当然,你也可以根据需要再增加一些属性,如字体、控件大小等,让控件使用者可以更加灵活地使用控件。
到这里,我需要向大家补充一点,复合控件创建中的很重要的一条是:任何构成控件 (Constituent Control) 的属性必须要通过加入复合控件的属性来公开,而不要直接把构成控件直接以 public 级别公开。比如说上面,我们就不应把 Label 控件的访问级别设为 public 来直接公开(默认是 private )。这样作的目的是让我们能更好地把握控件的数据安全,从而只把那些最需要的属性公开给控件用户。
** 5 ** ** .时间显示的处理。 ** 到现在,我们就可以增加代码来让我们的控件显示时间了。首先请把 timer1 的 Interval 属性设为 1000 ,也就是 1 秒的时隔。然后双击 timer1 ,在其 Tick 事件处理过程中增加以下代码:
label1.Text=System.DateTime.Now.ToLongTimeString();
这样,每隔一秒钟,我们的 Label 就会重新显示当前系统时间。最后,请双击 TimeLabel 控件上的空白处,在出现的 TimeLabel_Load 事件处理过程中增加以下代码来激活 Timer :
timer1.Enabled=true;
这样, Timer 就会忠心耿耿地开始计算时间,并更新 Label 上的时间文字了。
** 6 ** ** .事件处理。 ** 由于是继承自 UserControl 的控件,所以 TimeLabel 从一开始便拥有了 Click 、 DragDrop 、 FontChanged 等事件。我们现在要做的是增加一个自定义事件—— Tick ,以便通知使用我们控件的窗体时间已经改变了。因为我们只需要简简单单地让这个事件发生,所以不需创建我们自己的代理 (delegate) 函数,也不需创建特殊的事件处理事据对象。 OK ,请看下面的代码:
首先在 TimeLabel 类里增加 Tick 事件声明:
public event EventHandler Tick;
然后给该事件编写一个调用过程,请注意该过程的命名:
protected void OnTick (EventArgs e)
{
if(Tick!=null)
{
Tick(this, e);
}
}
另外,在上面处理过的 Timer 的 Tick 事件处理过程中,还应增加对 OnTick 的调用,代码如下:
private void timer1_Tick(object sender, System.EventArgs e)
{
label1.Text=System.DateTime.Now.ToLongTimeString();
OnTick(e);
}
这样,我们的控件就编写完成了,请生成该项目。为了试验它,我们需要创建一个新的 Windows 项目。步骤如下:
** 7 ** ** .创建试验项目。 ** 在 Visual C# .NET 中通过“文件”-“添加项目”-“新建项目”,创建一个新的 Windows 应用程序,命名为 TestTimeLabel ,并添入当前解决方案中,如图 3 :
** 8 ** ** .添加控件引用。 ** 在使用自定义控件之前,我们必须把控件添加到“工具箱”中。方法是:右击“工具箱”,点选“自定义工具箱”,在弹出的“自定义工具箱”对话框中选择“ .NET 框架组件”页,然后点击“浏览”,定位并打开我们刚才所创建的 TimeLabel 控件专有程序集( TimeLabel.dll ),使该控件出现在“ .NET 框架组件”列表中,如图 4 所示:
** **
点击“确定”即可把 TimeLabel 控件添加到“工具箱”中,如图 5 所示:
** 9 ** ** .使用控件。 ** 现在,我们就可以把我们创建的 TimeLabel 像其它控件一样拖放到 Windows 窗体上,设置它的属性和响应它的事件了。比如,可以在属性窗口中设置 TimeLabel 的 LabelBackColor 为你喜欢的颜色。当然,除 LabelBackColor 以外,还有大量的属性可供设置,而且如果大家愿意,还可以回到 TimeLabel 项目中再用上面说过的方法增加其它的属性,从而使控件功能和用户界面更加丰富。
** 10 ** ** .响应事件。 ** 前面我们给 TimeLabel 增加了一个 Tick 事件,每当时间显示改变之后发生。那么我们的程序怎样知道 Tick 事件已经发生、并对它做出反应呢?方法如下:
首先增加事件处理过程如下(名称可以自定,但必须要有 object 和 EventArgs 类型的参数,并且以 void 类型返回):
private void TickHandler(object sender, EventArgs e)
{
System.Diagnostics.Debug.WriteLine(timeLabel1.LabelText);
}
其次,在 Form.InitializeComponent 过程中把上述过程注册给 TimeLabel 的 Tick 事件:
this.timeLabel1.Tick+=new EventHandler(this.TickHandler);
这样,我们的试验项目就已经完成,可以调试了。试验程序启动界面如图 6 :
同时,在调试器的输出窗口中,每隔一秒都会有一条新的 Debug 记录写入,内容是 TimeLabel 的 LabelText 属性(即所显示的时间)。这说明我们的事件处理成功了:)
后记:本文通过一个简单的 demo 演示了如何使用 Visual C# .NET 创建一个简单的复合控件。大家可以按照项目或学习的实际需要来把这个例子进一步完善(比如说可以给控件增加自定义的图标等)。如果程序中有何不足之处或对创建控件有其它的见解,还望与我联系,我的邮件地址是: [email protected] 。