知识大全 一步一步创建Visual Basic .NET 控件

Posted 属性

篇首语:人无常识,百事难成。本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识大全 一步一步创建Visual Basic .NET 控件相关的知识,希望对你有一定的参考价值。

一步一步创建Visual Basic .NET 控件  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!

我从来没有真正想过要当一名 C++ 程序员 因为我太懒了 不能那么辛苦地工作 但我必须承认 我过去常常嫉妒那些 C++ 程序员 嫉妒他们编写可视控件的能力

  Visual Basic® 及其早期版本中的控件仅限于 复合 控件(由其他控件组成的控件) 这种控件称为 UserControl 在 Visual Basic 中编写能够在屏幕上呈现其特有可视外观的控件几乎是不可能的

  现在好了 可以使用功能强大的 Visual 编写各种类型的可视控件了!不仅可以编写复合的 UserControl 还能继承现有的控件(如 TextBox)并扩展其新功能 更重要的是 还可以从头编写能够呈现其特有界面的可视控件

  在本文中 我将从头创建一个完整的可视控件 以说明 Visual Basic NET 的后一种功能 该控件是一个 红绿灯 一个包含三个圆(分别代表红 黄 绿三个灯)的矩形 图 显示各个灯亮时该控件的外观 控件的背景颜色设置为系统颜色 ControlDark

  

  图 带有三个 TrafficLight 控件的窗体 每个控件亮不同的灯

  我们称它为 TrafficLight 控件 它可以通过代码或让用户单击灯来改变亮起的灯

  因为 TrafficLight 是一个可视的 Windows 窗体控件 它将继承 S  ystem Windows Forms 命名空间中的 Control 类 这样 它将具有很多预定义的属性 方法和事件 包括控制其外观的属性 如 ForeColor BackColor Size 和 Location 还包括事件 如 MouseOver 和 Click 您可以查看 NET 文档 获得 Control 类成员的完整列表

  红绿灯也需要具有特殊的属性和事件 如下所示

Status 属性 确定亮起哪种颜色的灯 必须为以下三个枚举值之一 StatusRed 红灯亮 StatusYellow 黄灯亮 StatusGreen 绿灯亮 BorderWidth 属性 红绿灯周围边框的宽度 StatusChanged 事件 当通过代码或由用户单击不同的灯改变 Status 属性的值时 触发该事件

  由于这些成员不属于 Control 基类 所以我们需要包括完整的代码以处理它们 我们还需要绘制边框和三个相应颜色的灯的代码 以便在屏幕上绘制红绿灯 最后 我们需要处理用户单击圆以更改亮起灯的操作 并在更改亮起的灯时更改 Status 属性

  为了使本示例尽可能接近实际应用环境 我们还将包括能够确保在 Visual Studio® NET IDE 中更好地使用控件的代码 我们为工具箱设置适当的图标 并包括能够使属性更好地与各属性窗口集成的逻辑   现在让我们开始吧

  第 步 创建类型正确的项目

  要创建一个保存 Windows 窗体控件的库 需要在 Visual 中启动一个新项目 选择 Windows Control Library(Windows 控件库)项目类型 然后将项目命名为 MyControls

  所创建的项目实际上可以保存多个 Windows 窗体控件 每个控件都属于其各自的类 但我们只需在其中创建一个控件

  第 步 更改基类

  在控件库中创建的类自动命名为 UserControl 默认情况下 从 UserControl 类继承 如果我们要创建复合控件 那非常容易 只需将其他控件从工具箱中拖到设计表面上即可

  但是 由于我们要从头创建自己的控件 因此需要做一些更改 将控件类的名称从 UserControl 更改为 TrafficLight 然后 将以下行

  Inherits System Windows Forms UserControl

  更改为

  Inherits System Windows Forms Control

  这样 使最一般的 Control 类成为基类 您会发现 不再显示可视设计表面 而是替换为组件设计表面

  为保持代码的一致性 也要将代码文件名从 UserControl VB 更改为 TrafficLight vb 可以在 Solution Explorer(解决方案资源管理器)中进行更改 右键单击代码文件的名称 并选择 Rename(重命名)

  还需要在类模块的顶部添加几行代码 将 Option Strict 设置为 On 并导入包含我们将来要用到的某些属性的命名空间 下面是要放到代码最上面的两行 Option Strict OnImports System ComponentModel

  第 步 实现属性和事件

  要实现 Status 属性 首先要为可能的属性值创建枚举 将以下几行插入以 Inherits 开始的行下面

   Public Enum TrafficLightStatusstatusRed = statusYellow = statusGreen = End Enum

  此枚举是公开的 也就是说使用该控件的窗体可以访问它

  在这些行下面添加以下三行

   Dim mStatus As TrafficLightStatus = TrafficLightStatus statusGreenDim msngBorderWidth As Single = !Public Event StatusChanged(ByVal NewStatus As TrafficLightStatus)

  前两行中的两个变量可用于存储 Status 和 BorderWidth 属性的属性值 还为这些属性设置了默认值 保存 BorderWidth 的变量必须为 Single 类型 因为它是绘制边框所用的图形语句需要的类型 默认值中的惊叹号也表明它是 Single 类型 此集合中的最后一行声明了 StatusChanged 事件

  现在 我们为 BorderWidth 属性编写代码 在标记为 Windows Form Designer Generated Code(Windows 窗体设计器生成的代码)的代码区域下插入以下行

   <DefaultValue( !) _Description( 红绿灯周围边框的宽度 )> _Public Property BorderWidth() As SingleGetReturn msngBorderWidthEnd GetSet(ByVal Value As Single)If msngBorderWidth <> Value ThenmsngBorderWidth = ValueMe Invalidate()End IfEnd SetEnd Property

  前两行包括使该属性更好地使用 IDE 的属性 DefaultValue 特性允许在 Properties(属性)窗口中将属性值重置为默认值(操作步骤稍后介绍) Description 特性提供选中该属性时在 Properties(属性)窗口底部显示的文本

  DefaultValue 特性还有一个技巧 如果将 TrafficLight 控件放到窗体上 并保留 BorderWidth 属性的默认值 那么窗体设计器将不生成设置属性值的代码行 这使它与其他 Windows 窗体控件没有什么区别 如果您查看典型控件(如 TextBox)的设计器生成的代码 您会发现只包括设置为非默认值的属性的代码行 我们赋予 TrafficLight 控件同样的能力

  Property Get 简单明了 Property Set 子句包括可视控件属性中常见的逻辑 设置属性时 重要的是在新属性值更改控件的外观时要能够重新绘制控件 因此 Set 子句负责确定传递的新值是否与属性中现有的值不相同 如果相同 则不执行操作 如果不同 则接受新值 然后访问控件的 Invalidate 方法 此方法表明 控件的可视区域已过期 控件需要重新绘制

  Status 属性的处理有些不同 因为它是枚举值 DefaultValue 特性没有为枚举属性提供自动重置能力 在这种情况下 DefaultValue 也无法告诉设计器何时停止设置属性值的代码 因此 Status 属性的实现中不需要 DefaultValue 特性 下面是 Status 属性的代码

   <Description( 红绿灯的状态(颜色) )> _Public Property Status() As TrafficLightStatusGetStatus = mStatusEnd GetSet(ByVal Value As TrafficLightStatus)If mStatus <> Value ThenmStatus = ValueRaiseEvent StatusChanged(mStatus)Me Invalidate()End IfEnd SetEnd Property

  看起来与 BorderWidth 属性的实现类似 只有一点不同 当 Status 属性发生改变时 除了强制重新绘制控件外 还会触发 StatusChanged 事件

  要在 Properties(属性)窗口中处理属性的自动重置 我们需要使用一种特殊的方法 由于我们的属性命名为 Status 因此必须将重置方法命名为 ResetStatus 重置方法只是恢复属性的默认值 以下是其代码

  

  Public

  Sub ResetStatus()Me Status = TrafficLightStatus statusGreenEnd Sub

  为了提示设计器何时需要包括一行代码以便设置 Status 属性 我们需要包括一个名为 ShouldSerializeStatus 的方法 当属性需要一行代码时 此方法返回布尔值 True 否则 则返回 False 以下是其代码

   Public Function ShouldSerializeStatus() As BooleanIf mStatus = TrafficLightStatus statusGreen ThenReturn FalseElseReturn TrueEnd IfEnd Function

第 步 绘制控件的外观

  要使控件具有一个可视的外观 我们需要在 Paint 事件中放置逻辑 然后 每次控件需要刷新其可视外观时 就会运行该逻辑

  Windows 窗体中的 Paint 逻辑使用 中 GDI+ 部分中的类 这些类基本上包括了 Windows API 图形功能 由于适合 NET 所以比 API 更易于使用 但是 有关它们的工作原理 需要理解以下几点

  在 Windows API 中 图形操作需要一个窗口句柄 有时称为 hWnd 在 GDI+ 中 它由 Graphics 对象取代 该对象不仅代表了绘图区域 还提供在该区域执行的操作(方法)

  例如 Graphics 对象具有以下方法 可用来绘制各种屏幕元素

  DrawCurve

  DrawEllipse

  DrawLine

  DrawPolygon

  DrawRectangle

  DrawString

  FillEllipse

  FillPolygon

  这些都是很容易理解的 只是可用方法的示例 一些更复杂的方法还允许旋转对象 我们将使用 DrawRectangle 方法绘制边框 使用 FillEllipse 方法绘制彩色的圆

  大多数绘图方法都要求使用 Pen 或 Brush 对象 Pen 对象用于绘制直线并确定直线的颜色和粗细 Brush 对象用于填充区域 确定填充区域所使用的颜色 以及一些特殊效果(例如 用位图填充区域) 我们将使用特殊的 Brush 效果使当前没有亮起的灯的颜色变暗

  下面是处理控件的 Paint 事件的代码

  Protected Overrides Sub OnPaint(ByVal pe As _ System Windows Forms PaintEventArgs)MyBase OnPaint(pe)

  Dim grfGraphics As System Drawing GraphicsgrfGraphics = pe Graphics

   首先绘制三个代表灯的圆 一个亮起 其余两个熄灭 DrawLight(TrafficLightStatus statusGreen grfGraphics)DrawLight(TrafficLightStatus statusYellow grfGraphics)DrawLight(TrafficLightStatus statusRed grfGraphics)

   现在绘制红绿灯周围的轮廓 用画笔绘制轮廓 将它涂成黑色 Dim penDrawingPen As New _System Drawing Pen(System Drawing Color Black msngBorderWidth)

   在控件上绘制红绿灯的轮廓 首先定义要绘制的矩形 Dim rectBorder As System Drawing Rectangle

  rectBorder X = rectBorder Y = rectBorder Height = Me Height rectBorder Width = Me Width grfGraphics DrawRectangle(penDrawingPen rectBorder)

   释放图形对象penDrawingPen Dispose()grfGraphics Dispose()

  End Sub

  首先使用基类绘制 它通常使用控件的背景颜色绘制背景 然后 从事件参数中获取控件的 Graphics 对象

  接下来 用一个函数画出三个圆 有关该函数的内容稍后介绍 请注意 我们必须向该函数传递一个 Graphics 对象的引用 同时还要指示要画的圆(红 黄 绿)

  然后是绘制轮廓的代码 声明一个具有适当位置和大小的矩形 然后传递给 Graphics 对象的 DrawRectangle 方法

  最后 图形对象激活其 Dispose 方法 使用 GDI+ 时 最好在完成图形对象后立即释放它们 这有助于清除操作系统绘图时所用的资源 如果要在 Windows® 或 Windows Me 中使用控件 管理图形资源就更加重要 因为这些操作系统处理这种资源的能力较差

  下面是绘制圆的函数

  Private Sub DrawLight(ByVal LightToDraw As TrafficLightStatus _ByVal grfGraphics As Graphics)

  Dim nCircleX As IntegerDim nCircleY As IntegerDim nCircleDiameter As IntegerDim nCircleColor As Color

   找到所有圆的 X 坐标和直径nCircleX = CInt(Me Size Width * )nCircleDiameter = CInt(Me Size Width * )Select Case LightToDrawCase TrafficLightStatus statusRedIf LightToDraw = Me Status ThennCircleColor = Color OrangeRedElsenCircleColor = Color MaroonEnd IfnCircleY = CInt(Me Size Height * )Case TrafficLightStatus statusYellowIf LightToDraw = Me Status ThennCircleColor = Color YellowElsenCircleColor = Color TanEnd IfnCircleY = CInt(Me Size Height * )Case TrafficLightStatus statusGreenIf LightToDraw = Me Status ThennCircleColor = Color LimeGreenElsenCircleColor = Color ForestGreenEnd IfnCircleY = CInt(Me Size Height * )

  End SelectDim bshBrush As System Drawing BrushIf LightToDraw = Me Status Then

  bshBrush = New SolidBrush(nCircleColor)ElsebshBrush = New SolidBrush(Color FromArgb( nCircleColor))End If

   绘制代表红绿灯的圆grfGraphics FillEllipse(bshBrush nCircleX nCircleY nCircleDiameter nCircleDiameter)

   释放笔刷bshBrush Dispose()

  End Sub

  这是整个控件中唯一的一个复杂图形 在 GDI+ 中 在要绘制椭圆的矩形中指定左上角的 X 坐标和 Y 坐标 然后指定矩形的高度和宽度即可绘制一个椭圆 我们分别将 X 坐标和 Y 坐标称为 nCircleX 和 nCircleY 因为我们要绘制一个圆 因此矩形的高度等于宽度 用变量 nCircleDiameter 来控制该值

  将 nCircleX 设置为刚好放到控件内(控件的宽度乘以 ) nCircleY 取决于要绘制哪个灯 可以设置成靠近控件的顶部(红灯) 大约向下三分之一(黄灯)或大约向下三分之二(绿灯) 直径 nCircleDiameter 设置为等于控件宽度的 %

  要绘制实心椭圆 还需完成一件事 即确定要使用的颜色 颜色取决于正在绘制哪个灯以及正在绘制的灯是否亮起 亮起的灯的颜色要比熄灭的灯的颜色亮

  创建绘图要使用的笔刷时需要使用这些颜色 如果正在绘制的灯是亮起的 即使用该颜色 如果绘制的灯是熄灭的 则要使用不同的方法实例化笔刷 下面是熄灭的灯所使用笔刷的代码行

  bshBrush = New SolidBrush(Color FromArgb( nCircleColor))

  这并不是 NET 中较好的方法名 但 FromArgB 方法的作用是创建笔刷 并通过将笔刷与背景颜色相结合来淡化颜色 第一个参数使用的数字介于 至 之间 数字越小 背景颜色渗透越深 我们使用的值为 它将大大降低处于熄灭状态的灯的颜色 您可以尝试对该参数使用不同的值(或将它设置成可设置属性) 以获得不同的效果

  最后 Graphics 对象的 DrawEllipse 方法绘制出该圆 函数结束 记住 该函数需要调用三次以绘制三个不同的圆 第 步 使控件响应用户

  要允许用户更改灯的颜色 必须检测到用户的鼠标单击操作 有经验的 Visual Basic 开发人员都知道 可以使用多种方法实现这一目的 我们使用最简单的一种方法 即检测 MouseUp 事件 下面是检测用户单击并更改 Status 属性以与之匹配的代码

  

  Private Sub TrafficLight_MouseUp(ByVal sender As Object _ByVal e As System Windows Forms MouseEventArgs) _Handles MyBase MouseUpDim nMidPointX As Integer = CInt(Me Size Width * )Dim nCircleRadius As Integer = nMidPointXIf Distance(e X e Y nMidPointX CInt(Me Size Height / )) _ < nCircleRadius ThenMe Status = TrafficLightStatus statusRedExit SubEnd IfIf Distance(e X e Y nMidPointX CInt(Me Size Height / )) _ < nCircleRadius ThenMe Status = TrafficLightStatus statusYellowExit Sub End IfIf Distance(e X e Y nMidPointX CInt(( * Me Size Height) / )) _ < nCircleRadius ThenMe Status = TrafficLightStatus statusGreenEnd If

  End Sub

  Private Function Distance(ByVal X As Integer _ ByVal Y As Integer _ ByVal X As Integer _ ByVal y As Integer) As IntegerReturn CInt(System Math Sqrt((X X ) ^ + (Y y ) ^ ))End Function

  事件处理非常简单 检查鼠标单击的位置和每个圆心之间的距离 (请注意 圆心分别位于控件下方 / / 和 / 的位置 如果不太明白 可以在纸上画出来看看 )如果计算出的距离小于圆的半径 则更改 Status 属性

  距离由 Distance 函数使用您可能在代数课中学过的公式计算 请注意 平方根函数是从 System Math 命名空间中获得的 数学函数通常都保存在该命名空间中

  第 步 清理

  为了使控件顺利地运作 我们还需要执行一些其他操作 例如 大小改变时需要重新绘制控件 而且 为了不改变控件的比例 我们需要检测影响大小的属性发生更改的时间 然后强制宽度等于高度的三分之一 下面是完成这两项任务的事件处理程序

  

  Private Sub TrafficLight_Resize(ByVal sender As Object _ByVal e As System EventArgs) Handles MyBase ResizeMe Invalidate()End Sub

  Private Sub TrafficLight_Layout(ByVal sender As Object _ByVal e As System Windows Forms LayoutEventArgs) _Handles MyBase LayoutSelect Case e AffectedPropertyCase Bounds Me Width = CInt(Me Height * )Case Else 不执行任何操作End SelectEnd Sub

  最后 设置控件在工具箱中使用的图标 控件已经有一个看似齿轮的默认图标 但是我们要使用 Visual 附带的红绿灯图标

  控件的工具箱图标是由名为 ToolboxBitmap 的类中的特性设置的 在以 Public Class 开始的行上面插入以下行

   <ToolboxBitmap( C:\\Program Files\\Microsoft Visual Studio NET\\Common \\Graphics\\icons\\Traffic\\TRFFC ICO )> _

注意 所有内容都应在一行中 为了便于阅读 我们在 Studio 后放置了一个回车 粘贴该代码时 要确保它们位于一行中 Studio 和 NET 之间只需一个空格 并删除回车 如果您已经将 Visual Studio NET 安装到其默认位置 那么上述代码将用 Visual Studio 目录中的图标设置该特性 如果您没有将 Visual Studio NET 安装到其默认位置 则需要相应地更改图标的路径名

  第 步 生成和测试控件

  现在 TrafficLight 控件的设计就完成了 选择 Build | Build MyControls(生成 | 生成 MyControls) 以创建最终的控件库

  要测试控件 我们需要一个 Windows 窗体项目 您可以在其他解决方案中执行此操作 但在开发控件所用的解决方案中执行会更容易 从菜单中选择 File | Add Project | New Project(文件 | 添加项目 | 新项目) 选择 Windows Application(Windows 应用程序)项目类型 将项目命名为 TestTrafficLight 单击 OK(确定) 启动测试所需的 Windows 应用程序

  必须先将 TrafficLight 控件放到工具箱中 才能将其拖放到测试应用程序的空白窗体 中 右键单击工具箱中的 Windows 窗体选项卡 然后选择 Customize Toolbox(自定义工具箱) 选择 NET Framework Components( NET Framework 组件)选项卡 然后单击 Browse(浏览)按钮 浏览到您的 MyControls 项目所在的位置 然后转到该项目的 /bin 目录 选择 MyControls dll 组件并单击 OK(确定) 现在 该对话框应如图 所示

  

  图 在 Customize Toolbox(自定义工具箱)对话框中 TrafficLight 控件被选中

  您可以看到 TrafficLight 控件旁边有一个复选标记 单击 OK(确定)按钮 在工具箱的 Windows Forms(Windows 窗体)选项卡上 TrafficLight 控件将出现在控件列表的底部 图 显示了底部为 TrafficLight 控件的工具箱

  

  图 工具箱底部的 TrafficLight 控件

  现在 您可以将 TrafficLight 控件拖放到 TestTrafficLight 的空白窗体 中 默认情况下 它被命名为 TrafficLight 您可以调整控件的大小 重新设置控件的属性 包括 Status 属性 该属性有一个下拉菜单 菜单中包含该属性的三个可能的值 请注意 调整控件的大小或更改其属性时 控件将在设计器中自动刷新

  要恢复属性的默认值 请将 Status 属性更改为 statusRed 然后 右键单击 Properties(属性)窗口中的 Status(状态)属性 并选择 Reset(重置) 如图 所示 该属性将更改回 statusGreen 如果将 BorderWidth 属性设置为 之外的其他值 也可以使用同样的方法恢复其默认值

  

  图 Properties(属性)窗口中 Status(状态)属性的 Reset(重置)选项 请注意窗口底部有关 Status(状态)属性的说明

  如果需要 还可以为控件插入 StatusChanged 事件 然后 可以使用该事件中的以下代码行查看更改后的状态

  MsgBox( 新状态为 & NewStatus ToString)

  要在操作中测试该控件 您需要启动 TestTrafficLight 项目 此时 它还不是该解决方案的启动项目 因此您需要解决它 在 Solution Explorer(解决方案资源管理器)中 右键单击 Solution(解决方案)名称 Solution Explorer(解决方案资源管理器)中的第一行 选择 Properties(属性) 然后将 Single Startup Project(单启动项目)设置从 MyControls 更改为 TestTrafficLight 然后单击 OK(确定)

  按 F 键启动该项目 将显示带有 TrafficLight 控件的窗体 测试控件 按下不同的灯 查看它们是否亮起 您还可以测试 BorderWidth 属性 尝试在代码中设置灯的 Status 属性

  小结

  尽管 TrafficLight 是一个简单的控件(虽然曾有开发人员要把它用到真实的项目中) 但它却显示了开发复杂控件所需要的所有原理 包括 在控件中添加属性 使用默认值和说明 使属性与 Visual Studio IDE 协调 在 Paint 事件中插入逻辑以绘制控件 在绘图逻辑中使用 GDI+ 为控件设置位图 以便在工具箱中显示

cha138/Article/program/net/201311/11983

相关参考

知识大全 Visual C#或Visual Basic创建Web应用程序(上)

VisualC#或VisualBasic创建Web应用程序(上)  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起

知识大全 Visual C#或Visual Basic创建Web应用程序(下)

VisualC#或VisualBasic创建Web应用程序(下)  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起

知识大全 从Visual Basic 6.0到Visual Basic.NET

从VisualBasic6.0到VisualBasic.NET  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来

知识大全 Visual Basic.Net基本语句

VisualBasic.Net基本语句  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  一Try…

知识大全 Visual Basic.Net实现TCP协议

VisualBasic.Net实现TCP协议  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!TCP协

知识大全 实战Visual Basic.Net对话框

实战VisualBasic.Net对话框  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  对话框和

知识大全 使用Visual Basic.NET重载事件处理程序

使用VisualBasic.NET重载事件处理程序  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧! 

知识大全 Visual Basic.NET中组件的叠加使用

VisualBasic.NET中组件的叠加使用  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  状

知识大全 Visual Basic .Net打造个性化菜单

VisualBasic.Net打造个性化菜单  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  菜单

知识大全 使用 Visual Basic .NET 访问注册表

使用VisualBasic.NET访问注册表  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!使用Vi