C#开发自定义控件方法探讨

时间:2022-09-13 10:22:15

C#开发自定义控件方法探讨

摘要:针对当前开发工具提供的系统控件的不足,通过一个自定义控件的开发实例,分析和讨论了用C#进行自定义控件开发的方法。该方法可以应用于有特殊要求的软件开发。

关键词:系统控件;自定义控件;软件开发

中图分类号:TP311文献标识码:A文章编号:1009-3044(2007)15-30797-02

Discussion of the Technique of Self-defined Controls Based on C#

YAO Ming,LI Jia-lan

(Dept. of Computer Science and Technology,Maoming University,Maoming 525000,China)

Abstract:To solve the lack of system-defined controls within current develop tools, with a developing instance of a self-defined control, the developing technique of self-defined controls is analyzed and discussed based on C#. This technique can be used for software development with special requirements.

Key words:system-defined control; self-defined control; software development

1 引言

使用C#进行项目开发时,其所提供的控件常常不能满足用户的特殊需求。例如,在进行报表软件的开发时,需要生成足够灵活并且与动态数据绑定的报表单元格元素控件,而C#所提供的系统控件不能满足开发要求。此时必须开发自定义控件。本文通过报表单元格元素控件的开发,对用C#开发自定义控件的一般方法进行探讨。

2 自定义控件简介

组件是指一段经常用到的公共代码,封装在某个单元模块中。在.Net Framework中,一个类通过实现ponentModel.IComponent接口而成为组件[1]。

如果一个组件具有用户接口或界面,就称之为控件。控件可以直接通过界面与用户进行交互。控件的开发方法以面向对象方法为基础,它是界面、属性、方法、事件的一个封装。它实现了部分功能,能够被很好地调用。

用户通过继承和修改系统控件库所提供的控件,使其拥有新的属性、方法和事件处理,就可以得到自定义控件。

用C#可以开发两种不同类型的自定义控件[1]。其中一种是用户控件,开发中比较常见。这类控件一般用于把控件的用户界面和功能封装在一起,或者把几个其他控件组合在一起,改善控件的界面。这种控件继承自UserControl类,根据现有控件的功能创建而成。本文主要讨论这种控件的开发方法。

3 自定义控件的开发

自定义控件要具有系统原有控件的风格,同时还要实现用户的可操作性,则其必须在支持系统提供的专有接口的同时,对系统控件的功能进行扩展。总结其开发过程,可以分成四个阶段:自定义功能的提取、基础控件的选择、功能的实现和自定义控件的生成。

3.1 自定义功能的提取

自定义功能是指为满足用户的要求,系统对基础控件进行扩充的功能。自定义功能提取的目的,是明确自定义控件将要实现的功能和显示的信息,以便其与系统控件提供的功能相比较,选取合适的系统控件。设计中的报表单元格元素,在表现形式上就是控件。这种控件要求可以移动、改变大小、设置边框;可以设置背景颜色/图片;可以绑定动态数据,能够显示文字或数据。因此,有待开发的控件必须具有上述的功能特点。

选取功能需求之后,需要对其进行分析。对于某些系统控件可以提供的功能不予考虑,重点分析系统控件没有提供的功能,提取那些需要做很大改动或难以实现的功能作为该控件的特征功能。在报表单元格元素控件的功能要求中,背景的设置和文字的显示不予考虑,大小的改变可以在系统控件的基础上进行比较小的改动,也不予考虑,所以其特征功能就是移动、边框设置和数据绑定。特征功能将作为功能的实现的重要目标,而非特征功能将作为基础控件的选择依据。

3.2 基础控件的选择

根据前一阶段中提到的非特征功能,比较现有系统控件提供的基本功能,选择符合条件最多的作为基础控件。一般在选择基础控件的时候,优先选择常用的控件。根据前面的分析,考虑能进行背景设置和文字显示的常见控件是TextBox,因此该单元格元素的基础控件选择TextBox。

3.3 自定义功能的实现

自定义功能的实现是自定义控件开发中的关键,要求自定义控件对原有的控件进行重载,添加自定义属性,实现自定义事件处理,通过事件的响应和属性的设置来满足用户要求。

报表单元格元素控件必须为设计者(用户)提供自由设计报表的各种条件,用户根据自己的需要对报表元素(控件)进行各种操作,从而达到自己满意的效果。根据这种要求,对原有的控件进行重载,添加自定义属性、自定义事件,通过事件的响应和属性的设置来满足用户要求。功能的具体实现过程为:首先扩展控件的基类型,然后添加自定义属性,编写自定义事件的处理程序。

3.3.1 扩展系统控件

原有功能的扩展是对某些系统控件提供的功能进行改进的过程。其具体实现方法是重载被扩展功能所对应的基类方法。对于报表单元格,其位置、大小等的改变都是通过用户的鼠标操作来引发的。系统监听属性框,一旦用户手动更改控件的属性值,系统将自动判断更改的属性值,并及时更改该属性对应的表现形式,同时系统还将更改并保存控件对应的属性值。在此应重载控件的鼠标事件类的相应方法OnMouseDown()与OnMouseUp(),当鼠标按下与鼠标松开时对自定义属性进行处理。

3.3.2 添加自定义属性

自定义控件需要自定义属性,以记录必要的信息。控件的属性是控件外在表现形式的数据(变量)表示。将变量转化为属性,方便了对这种数据的访问和安全控制。用户可以通过对属性的设置来更改控件的表现形式。为给用户提供更全面的信息,同时也为开发者降低实现难度,有时必须对原有控件的属性进行扩充。

在显示元素属性设置的实现时,控件生成以后,其属性便已经初始化,并显示在属性框中。一旦控件的属性更改,属性框的值也及时更新,并同时更改其表现形式。要实现边框的任意设置,控件需要添加边框属性。在用户对控件进行边框设置的时候,其属性值必须相应地改变,并且显示在界面上(用属性框显示)。属性的定义格式为:

//声明部分

private class_propertyTemp = new class(); //用于声明记录属性值的临时变量

//属性设置部分

pubic class PropertyName //PropertyName为属性在显示和使用时的名称

{

get {return_propertyTemp;} //获取属性值权限

set {_propertyTemp = value;} //设置属性值权限

}

3.3.3 编写自定义事件

自定义控件还需要自定义的事件处理程序来处理不同的事件,以达到用户需要的结果。用户在操作报表元素(控件)的时候,控件必须响应的事件包括拖拽、变大、缩小、选中变色、边框显示等。通过控件对这些事件的响应来改变其表现形式。C#中事件是通过委托机制来实现的。控件事件的处理过程为:控件通过监听鼠标事件,来判断当前鼠标将要进行的事件,将其对应的事件添加到事件委托中,等待事件的激活。一旦事件激活便自动执行事件处理程序[2]。事件处理完之后立即更新控件的属性,并能够显示在属性框中。自定义事件处理也必须按照此过程进行。在OnMouseDown()与OnMouseUp()方法中编写控件属性的处理过程如下:

public void OnMouseDown(object sender, MouseEventArgs e)

{

……

Process the propertyName; //对属性的处理过程

if(e.Button == System.Windows.Forms.MouseButtons.Left)

{

///向控件Control的鼠标移动MouseMove事件队列中添加由新建委托///MyMouseEventHandler处理的DragMouseMove事件。

this.Control.MouseMove += new MyMouseEventHandler(DragMouseMove); }

……}

public void OnMouseUp(object sender, MouseEventArgs e)

{……

this.propertyGrid.SelectedObject = this.Control.PropertyName;

//显示修改后的属性。this.propertyGrid表示属性框。

……}

报表元素控件需要特殊处理鼠标的拖拽,以完成控件的移动,大小改变等。OnMouseDown()方法事例代码中的if语句块表示当鼠标左键按下时,控件Control的拖拽事件DragMouseMove将被添加到其新建的事件委托MyMouseEventHandler中,等待激活。当鼠标开始移动时,事件DragMouseMove被激活,系统自动运行DragMouseMove中的事件处理程序,对控件的位置以及顶点坐标处理:

public void DragMouseMove(object sender, MouseEventArgs e)

{this.Location = new Point(this.Location.X + e.X - tempX,this.Location.Y + e.Y - tempY);

this.Left = this.Location.X;

this.Top = this.Location.Y;}

新建事件委托部分代码如下:

//声明并实例化一个鼠标事件委托。

public delegate void MyMouseEventHandler(object sender, MouseEventArgs e);

public event MyMouseEventHandler myMouseEventHandler;

由于新建委托的事件列表类型是系统提供的鼠标事件MouseEventArgs,因此该委托的事件处理过程与系统的鼠标事件处理过程相同。如果使用自己定义的处理过程来处理事件,则须重写这个事件列表。有关委托的内容可参看文献[3]。

3.4 自定义控件的生成

完成了上述工作之后,再编译生成DLL文件,即自定义控件的生成。生成后的自定义控件可以像其他控件一样被应用程序正常调用。很多开发环境都为开发者提供了控件的生成这项功能。在.Net环境只需一步操作就可以得到控件的DLL文件。在需要用到的时候直接引用该DLL文件即可。

4 自定义控件应用中的注意点

由于自定义控件实现了特殊的功能,而这些功能必定牵涉到某些特殊的数据。要保证自定义控件运行的正确性,必须要保证控件操作的数据的准确性。对于已经提供组件扩展功能的.Net开发平台,自定义控件的引用可以参考帮助文档,按规定步骤操作即可。

一般大型的应用程序都包含多个区域。各个区域之间必然存在某些联系,而这些联系也将影响到控件在各窗口之间的调用[4]。窗口间的调用主要发生在控件的操作和属性的同步显示时。控件的操作必将影响到控件的属性值,而属性的显示必须使用到这些属性值。要解决调用问题,则要通过事件与委托。委托可以使事件源与控件处于不同区域中。这样就可以保证对控件的操作与其属性值保持同步。

窗口间的调用问题还表现在不同窗口间的数据的传递。当两个处在不同区域或层次上的控件(包括系统控件)共同处理同一数据时,窗口间的值传递问题便产生。可以通过参数形式的值/引用传递来实现数据共用或通过公用类存储数据这两种不同的解决方案来实现数据共用。前者实现方法简单直接,实现目的明确,但传递的数据不宜过多,数据的安全性较差,一旦数据作为参数传递给方法,方法即可对其进行一些危险的操作,因此开发者必须在方法中对这种操作加以限制;后者比较容易控制数据在不同空间使用时的安全性,而且适合各种数据形式,但实现起来比较麻烦。

5 结束语

使用C#在一些专业领域的软件开发中,由于用户有特殊要求,常要进行自定义控件的开发。自定义控件开发的主要技术要点是添加自定义属性和编写自定义事件处理,其中编写自定义事件处理程序是自定义控件开发的核心部分。自定义控件可以像其它系统控件一样使用,但是须注意控件所对应的数据的正确性以及与其它窗口之间的调用问题。

参考文献:

[1]Karli Watson,Marco Bellinaso,等. 康博,译. C#入门经典[M]. 北京:清华大学出版社,2002:577,365.

[2]Richard Wiener. Delegates and Events in C#[J]. JOURNAL OF OBJECT TECHNOLOGY, 2004,3(5):78-85.

[3]何卓华, 唐平. Visual C#中委托特性的原理及其应用[J]. 现代计算机, 2003,141:65-67.

[4]Harald Haller. Design of Large .NET Applications: Best Practices[J]. JOURNAL OF OBJECT TECHNOLOGY. 2003,3(2):11-17.

上一篇:《完美世界》五行相克的玄妙 下一篇:移动商务新宠――UMPC笔记本导购