c#自定义控件开发.docx

上传人:b****9 文档编号:25326068 上传时间:2023-06-07 格式:DOCX 页数:15 大小:41.46KB
下载 相关 举报
c#自定义控件开发.docx_第1页
第1页 / 共15页
c#自定义控件开发.docx_第2页
第2页 / 共15页
c#自定义控件开发.docx_第3页
第3页 / 共15页
c#自定义控件开发.docx_第4页
第4页 / 共15页
c#自定义控件开发.docx_第5页
第5页 / 共15页
点击查看更多>>
下载资源
资源描述

c#自定义控件开发.docx

《c#自定义控件开发.docx》由会员分享,可在线阅读,更多相关《c#自定义控件开发.docx(15页珍藏版)》请在冰豆网上搜索。

c#自定义控件开发.docx

c#自定义控件开发

自定义控件基础知识

一、概述

Windows窗体控件是可再次使用的组件,它们封装了用户界面功能,并且可以用于客户端Windows应用程序。

“Windows窗体”不仅提供了许多现成控件,还提供了自行开发控件的基础结构。

可以组合现有控件、扩展现有控件或创作自己的自定义控件。

Windows窗体控件是从System.Windows.Forms.Control直接或间接派生的类。

以下列表描述了开发Windows窗体控件的常见方案:

·组合现有控件来创作一个复合控件。

复合控件封装有一个可以作为控件重复使用的用户界面。

可视化设计器为创建复合控件提供了有力的支持。

要创作一个派生自System.Windows.Forms.UserControl的复合控件。

基类UserControl为子控件提供了键盘路由并使子控件可以作为一个组进行工作。

·扩展现有控件,对其进行自定义或为其添加功能。

可以通过从任何Windows窗体控件派生控件并重写或添加属性、方法和事件的方式来自定义Windows窗体控件。

·创作一个不是通过组合或扩展现有控件而形成的控件。

在这种方案中,需从基类System.Windows.Forms.Control派生控件。

可以添加和重写基类的属性、方法和事件,来制作功能强大,能满足自己需求的控件。

Windows窗体控件的基类System.Windows.Forms.Control为客户端Windows应用程序中的外观显示提供了所需的途径。

Control提供了一个窗口句柄,用来处理消息路由并提供鼠标和键盘事件及许多其他用户界面事件。

还提供了高级布局,并具有用于外观显示的特定属性,如ForeColor、BackColor、Height、Width和许多其他属性。

此外,它还提供了安全性、线程支持以及与ActiveX控件的交互性。

由于基类提供了很多基础结构,使得开发自己的Windows窗体控件变得相对简单。

二、编写简单的自定义控件

2.1、简单控件例子

下面的示例创建一个简单控件,该控件通过处理Paint事件显示其Text属性的值。

为了创建此控件和处理事件,必须创建一个从Control继承的类,并创建一个重写OnPaint方法的方法。

publicclassHelloWorldControl:

Control

{

protectedoverridevoidOnPaint(PaintEventArgse)

{

       RectangleFrect=newRectangleF(ClientRectangle.X,

                                        ClientRectangle.Y,

                                        ClientRectangle.Width,

                                        ClientRectangle.Height);

       e.Graphics.DrawString(this.Text,Font,newSolidBrush(ForeColor),rect);

   }

}

2.2、我们在VS2005中创建自定义控件的步骤:

1.打开vs2005,文件/新建/项目。

2.出现“新建项目”对话框。

3.在“名称”框中,键入项目名称,“位置”框选择要存储的位置。

4.从“语言”列表中选择要使用的编程语言。

5.单击“添加”,这时一个自定义控件工程已经建成,生成一下,就制作了一个简单的自定义控件,只不过没有任何功能。

6.向新用户控件添加任何标记和控件,并为该用户控件添加执行的所有任务(例如,处理控件事件或从数据源读取数据)添加代码。

2.3、检查控件的设计时行为

1.启动VS2005。

2.通过从“文件”菜单单击/新建/项目/Windows应用程序,添加新窗体。

3.右键“工具箱/选择项…”,在弹出的“选择工具箱项”对话框中点下面的浏览按钮选择要使用控件的DLL;确定后,该控件出现在工具箱的底部。

4.选择该控件并将其添加到窗体中。

将看到该控件出现在窗体上。

5.如果从上一个示例添加控件,您将注意到即使如此简单的控件都具有一整套属性和广泛的设计时行为。

此默认行为是从Control类继承的。

三、为控件添加属性

控件应该定义属性而不是公共字段,因为可视化设计器在属性浏览器中显示属性,而不显示字段。

属性就像智能字段。

属性通常具有带访问函数的专用数据成员,在语法上属性被作为类的字段进行访问。

(虽然属性可以具有不同的访问级别,但此处的讨论将重点放在公共访问这种更加常见的情况上。

属性定义通常由以下两部分组成:

1、专用数据成员的定义。

  privateintnumber=0;

2、使用属性声明语法对公共属性进行的定义。

该语法通过get和set访问函数将专用数据成员和公共属性关联起来。

       publicintMyNumber

   {

   get

      {

         returnnumber;

      }   

   set

      {

         number=value;

      }

   }

value这个术语是属性定义语法中的一个关键字。

在呼叫代码中,将变量value分配给属性。

value的类型必须同它被分配到的属性的声明类型相同。

虽然属性定义中通常包含专用数据成员,但这不是必需的。

get访问器不用访问私有数据成员就可以返回值。

get方法返回系统时间的属性就属于这种情况。

属性启用数据隐藏,访问器方法隐藏属性的实现。

定义属性时需考虑以下重要的注意事项:

1、  必须将属性应用于定义的属性。

属性用来指定设计器显示属性的方式。

2、  如果改变属性将影响控件的外观显示,请从set访问器中调用Invalidate方法(从Control继承该方法)。

Invalidate随后调用OnPaint方法,该方法将重新绘制控件。

为提高效率起见,对Invalidate的多次调用将产生对OnPaint的一次调用。

3、  .NETFramework类库为常见数据类型(如整数、小数、布尔值和其他数据)提供了类型转换器。

类型转换器的目的通常是用来提供字符串到数值的转换(从字符串数据转换为其他数据类型)。

常见数据类型与默认类型转换器(将数值转换为字符串,并将字符串转换为相应数据类型)相关联。

如果定义了自定义(即,非标准)数据类型的属性,则应用的属性必须将类型转换器指定为与该属性相关联。

还可以使用属性使自定义UI类型编辑器与某个属性相关联。

UI类型编辑器提供了一个用来编辑属性或数据类型的用户界面。

颜色选择器是UI类型编辑器的一个示例。

例:

首先创建一个名为DrawingMode的简单枚举。

       publicenumDrawingMode

       {

           Happy=0,

           Sad=1,

           Angry=2

       }

接着,向该控件添加MyDrawingMode属性。

      privateDrawingModemyDrawingMode;

      [Browsable(true),Category("Appearance")]

       publicDrawingModeMyDrawingMode

       {

           get

           {

               returnmyDrawingMode;

           }

           set

           {

               myDrawingMode=value;

               SetColors();

           }

       }

对SetColors方法的调用只是根据myDrawingMode的值设置控件的BackColor和ForeColor。

向控件添加下面的代码。

       privatevoidSetColors()

       {

           switch(myDrawingMode)

           {

               caseDrawingMode.Happy:

                   this.BackColor=Color.Yellow;

                   this.ForeColor=Color.Green;

                   break;

               caseDrawingMode.Sad:

                   this.BackColor=Color.LightSlateGray;

                   this.ForeColor=Color.White;

                   break;

               caseDrawingMode.Angry:

                   this.BackColor=Color.Red;

                   this.ForeColor=Color.Teal;

                   break;

               default:

                   this.BackColor=Color.Black;

                   this.ForeColor=Color.White;

                   break;

           }

       }

现在可以向控件的paint方法添加代码,来绘制控件的样式,也可以添加现有的控件来组合实现想要的功能(例子里面有)。

       privatevoidUserControl1_Paint(objectsender,PaintEventArgse)

       {

           GraphicscurG=e.Graphics;

           PencurPen=newPen(Color.Black);

           RectanglecurRect=newRectangle(0,0,Width-2,Height-3);

           curG.DrawRectangle(curPen,curRect);

           curG.DrawEllipse(curPen,curRect);

       }

四、为控件添加添加事件

事件(Event)

事件是对象发送的消息,以发信号通知操作的发生。

操作可能是由用户交互(例如鼠标单击)引起的,也可能是由某些其他的程序逻辑触发的。

引发事件的对象称为事件发送方。

捕获事件并对其作出响应的对象叫做事件接收方。

在事件通信中,事件发送方类不知道哪个对象或方法将接收到(处理)它引发的事件。

所需要的是在源和接收方之间存在一个媒介(或类似指针的机制)。

.NETFramework定义了一个特殊的类型(Delegate),该类型提供函数指针的功能。

代理(delegate)

delegate是C#中的一种类型,它实际上是一个能够持有对某个方法的引用的类。

与其它的类不同,delegate类能够拥有一个签名(signature),并且它只能持有与它的签名相匹配的方法的引用。

这样,代理就等效于一个类型安全函数指针或一个回调。

它允许你传递一个类A的方法m给另一个类B的对象,使得类B的对象能够调用这个方法m。

但与函数指针相比,delegate有许多函数指针不具备的优点。

首先,函数指针只能指向静态函数,而delegate既可以引用静态函数,又可以引用非静态成员函数。

在引用非静态成员函数时,delegate不但保存了对此函数入口指针的引用,而且还保存了调用此函数的类实例的引用。

其次,与函数指针相比,delegate是面向对象、类型安全、可靠的受控(managed)对象。

也就是说,runtime能够保证delegate指向一个有效的方法,你无须担心delegate会指向无效地址或者越界地址。

实现一个delegate是很简单的,通过以下3个步骤即可实现一个delegate:

1.声明一个delegate对象,它应当与你想要传递的方法具有相同的参数和返回值类型。

2.创建delegate对象,并将你想要传递的函数作为参数传入。

3.在要实现异步调用的地方,通过上一步创建的对象来调用方法。

下面是一个简单的例子:

publicclassMyDelegateTest

{

   //步骤1,声明delegate对象

   publicdelegatevoidMyDelegate(stringname);

   //这是我们欲传递的方法,它与MyDelegate具有相同的参数和返回值类型

   publicstaticvoidMyDelegateFunc(stringname)

   {

       Console.WriteLine("Hello,{0}",name);

   }

   publicstaticvoidMain()

   {

       //步骤2,创建delegate对象

     MyDelegatemd=newMyDelegate(MyDelegateTest.MyDelegateFunc);

       //步骤3,调用delegate

       md("sam1111");

   }

}

事件处理

C#中的事件处理实际上是一种具有特殊签名的delegate,象下面这个样子:

publicdelegatevoidMyEventHandler(objectsender,MyEventArgse);

其中的两个参数,sender代表事件发送者,e是事件参数类。

MyEventArgs类用来包含与事件相关的数据,所有的事件参数类都必须从System.EventArgs类派生。

当然,如果你的事件不含特别的参数,那么可以直接用System.EventArgs类作为参数。

结合delegate的实现,我们可以将自定义事件的实现归结为以下几步:

1:

定义delegate对象类型,它有两个参数,第一个参数是事件发送者对象,第二个参数是事件参数类对象。

2:

定义事件参数类,此类应当从System.EventArgs类派生。

如果事件不带参数,这一步可以省略。

3:

定义事件处理方法,它应当与delegate对象具有相同的参数和返回值类型。

4:

用event关键字定义事件对象,它同时也是一个delegate对象。

5:

用+=操作符添加事件到事件队列中(-=操作符能够将事件从队列中删除)。

6:

在需要触发事件的地方用调用delegate的方式写事件触发方法。

一般来说,此方法应为protected访问限制,既不能以public方式调用,但可以被子类继承。

名字是可以是OnEventName。

7:

在适当的地方调用事件触发方法触发事件。

下面是一个例子,例子模仿容器和控件的模式,由控件触发一个事件,在容器中捕捉并且进行处理。

事件的触发者:

////

///事件的触发者

///

publicclassControl

{

   publicdelegatevoidSomeHandler(objectsender,System.EventArgse);

   publiceventSomeHandlerSomeEvent;

   publicControl()

   {

       //这里使用的delegate必须与事件中声名的一致

       this.SomeEvent+=newSomeHandler(this.ProcessSomeEvent);

   }

   publicvoidRaiseSomeEvent()

   {

       EventArgse=newEventArgs();

       Console.Write("Pleaseinput'a':

");

       strings=Console.ReadLine();

       //在用户输入一个小a的情况下触发事件,否则不触发

       if(s=="a")

       {

           SomeEvent(this,e);

       }

   }

   //事件的触发者自己对事件进行处理,这个方法的参数必须和代理中声名的一致

   privatevoidProcessSomeEvent(objectsender,EventArgse)

   {

       Console.WriteLine("hello");

   }

}

事件的接收者:

////

///事件的接收和处理者

///

classContainer

{

   privateControlctrl=newControl();

 publicContainer()

   {

       //这里使用的delegate必须与事件中声名的一致

       ctrl.SomeEvent+=newControl.SomeHandler(this.ResponseSomeEvent);

       ctrl.RaiseSomeEvent();

   }

   publicstaticvoidMain()

   {

       Containerpane=newContainer();

       Console.ReadLine();

   }

   //这是事件的接受者对事件的响应

   privatevoidResponseSomeEvent(objectsender,EventArgse)

   {

       Console.WriteLine("Someeventoccur!

");

   }

}

程序运行的结果如下:

pleaseinput'a':

a

hello

Someeventoccur!

五、其他属性设置

  自定义控件工程建立,控件设置,属性事件的添加完成以后,生成项目,控件就已经制作完成了,可以在测试工程中使用,这里还有许多设置属性,需要我们了解,比如(下图)我们自己制作的控件显示的图标总是一个齿轮。

  

  而我们看到的工具箱上的每个控件都有自己的图标,我们可以通过下面语句为自己制作的控件添加图标。

[ToolboxBitmap(@"D:

\ProgramFiles\qq\AirDLIcon\1381love.ico")]

publicpartialclassUserControl1:

UserControl

{………….}

即在控件类前面加上ToolboxBitmap属性,属性参数指向一个图片的地址就可以了,加上这句程序以后,生成的控件如下图,图标变成了一个漂亮的心。

  

再比如,我自己定义了一个属性,如果不进行设置,是不会在属性窗口显示的,也就是我们在用控件的时候不能够通过可视化的界面对其进行设置,想让它在属性窗口显示,就要用Browsable属性了,如下面的例子。

       publicenumDrawingMode{Happy=0,Sad=1,Angry=2}

       privateDrawingModemyDrawingMode;

       [Browsable(true)]

       publicDrawingModeMyDrawingMode

       {

           get

           {

               returnmyDrawingMode;

           }

           set

           {

               myDrawingMode=value;

           }

       }

  

像这样的属性还可以组合使用,例如上面的例子,我在Browsable属性后面再加上一个Category属性,让它的参数等于Appearance,这时我们自己定义的属性就从属性框中的杂项转到了外观项里面了,如图:

[Browsable(true),Category("Appearance")]

publicDrawingModeMyDrawingMode

       {

           get

           {

               returnmyDrawingMode;

           }

           set

           {

               myDrawingMode=value;

           }

}

  

  

像这样的属性有很多,我主要罗列下面这些,在使用的时候大家可以参照。

Browsable

适用于属性和事件,指定属性或事件是否应该显示在属性浏览器中。

Category

适用于属性和事件,指定类别的名称,在该类别中将对属性或事件进行分组。

当使用了类别时,组件属性和事件可以按逻辑分组显示在属性浏览器中。

Description

适用于属性和事件,定义一小块文本,该文本将在用户选择属性或事件时显示在属性浏览器底部。

Bindable

适用于属性指定是否要绑定到该属性。

DefaultProperty

适用于属性,(将此特性插入类声明前。

)指定组件的默认属性。

当用户单击控件时,将在属性浏览器中选定该属性。

DefaultValue

适用于属性,为属性设置一个简单的默认值。

Editor

适用于属性,指定在可视设计器中编辑(更改)属性时要使用的编辑器。

Localizable

适用于属性,指定属性可本地化。

当用户要本地化某个窗体时,任何具有该特性的属性都将自动永久驻留到资源文件中。

DesignerSerializationVisibility

适用于属性,指定显示在属性浏览器

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 工作范文 > 行政公文

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1