重拾VB616:Object Model, Collection Class, and ActiveX Designer

来自MSDN-2001-OCT: Visual Tools and Languages/Visual Studio 6.0 Documentation/Visual Basic Documentation/Using Visual Basic/Programmer’s Guide/Part 2: What Can You Do With Visual Basic/Programming with Objects/Object Models

1. How to keep track of all object references

(1) According to COM rules,the only information you can depend on is whether or not the reference count is zero. You know when the reference count reaches zero,because your object's Terminate event occurs.

To make using objects more efficient,the Component Object Model (COM) specifies a number of complex shortcuts to its reference counting rules. The net result is that you couldn't trust the value of the reference count even if you had access to it.

(2) Declare your object variables as class types,instead of As Object.

(3) For collections of object references,don't use the Visual Basic Collection object by itself.

(4) Organize your object into a hierarchy,so that it's easy to walk through the whole model and reports on all the existing objects.

(5) Don't declare variables As New,because if you use one after you've set it to Nothing,Visual Basic obligingly creates another object.

(6) Circular references are the most difficult kind to shut down cleanly.

2. Object Models

(1) 可以用成员对象的办法来express对象之间的hierarchy。比如:

' Code for the Declarations section of the
' SmallBusiness class module.
Public Name As String
Public Product As New Product
Public Employees As New Collection
Public Customers As New Collection

Object properties work well when the relationship between objects is one-to-one. It frequently happens,however,that an object of one type contains a number of objects of another type. 这时候我们就要用collection。

(2) Class Builder creates robust object properties and collection classes,and allows you to rearrange your model easily.

(3) Tip When you assign a Parent property to an object in a collection,don't use a reference to the Collection object. The real parent of the object is the object that contains the collection. If the Parent property points to the collection,you'll have to use two levels of indirection to get to the real parent — that is,obj.Parent.Parent instead of obj.Parent.

(4) One of the biggest problems with Parent properties is that they create circular references. 解决的办法是给父亲object设计一个teardown方法,先把它的所有孩子都set nothing,然后再set它自己nothing.

When a Collection object is destroyed,Visual Basic sets all the object references it was holding to Nothing.

If there are variables anywhere in your program that still contain references to the SmallBusiness object,or to any of the objects it contains,those objects won't be destroyed. Part of the cleanup for your program must be to ensure that all object variables everywhere are set to Nothing.

To test whether this is happening,you may want to add some debugging code to your objects. For example,you can add the following code to a standard module:

VB.net语言: Dim frm As New Form1
' Global debug collection
Public gcolDebug As New Collection

' Global function to give each object a unique ID.
Public Function DebugSerial() As Long
Static lngSerial As Long
lngSerial = lngSerial + 1
DebugSerial = lngSerial
End Function

In each class module,you can put code similar to the following. Each class provides its own name where "Product" appears.

' Storage for the debug ID.
Private mlngDebugID As Long

Property Get DebugID() As Long
DebugID = mlngDebugID
End Property

Private Sub Class_Initialize()
mlngDebugID = DebugSerial
' Add a string entry to the global collection.
gcolDebug . Add "Product Initialize; DebugID=" _
& DebugID , CStr( DebugID)
End Sub

Private Sub Class_Terminate()
' Remove the string entry,so you know the object
' isn't around any more.
gcolDebug . Remove CStr( DebugID)
End Sub

At any time,you iterate over the global collection to see what objects haven't been destroyed.

3. Creating Your Own Collection Classes

(1) The ID property is the key for retrieving or deleting an Employee object from the collection,so it must be set once and never changed. This is accomplished with a Static Boolean variable that is set to True the first time the property is set. The property can always be read,because there is a Property Get.

Option Explicit
' Properties of the Employee class.
Public Name As String
Public Salary As Long

' Private data for the write-once ID property.
Private mstrID As String

Property Get ID() As String
ID = mstrID
End Property

' The first time the ID property is set,the static
' Boolean is also set. Subsequent calls do nothing.
' (It would be better to raise an error,instead.)
Property Let ID( strNew As String)
Static blnAlreadySet As Boolean
If Not blnAlreadySet Then
blnAlreadySet = True
mstrID = strNew
End If
End Property

(2) There are three general approaches you can take to implementing object containment using collections.

a) Public Collection: In the SmallBusiness class module,declare an Employees variable As Collection,and make it Public. This is the cheap solution.

The Collection object's very flexibility betrays it — you can put anything into a Collection,including the KitchenSink object.

b) Private Collection: In the SmallBusiness class module,declare an mcolEmployees variable As Collection,and make it Private. Give the SmallBusiness object a set of methods for adding and deleting objects. This is the least object-oriented of the three designs.

You can gain some robustness by making the Collection object private,but you lose the ability to use For Each … Next with the collection.

c) Implement your own collection class,by creating a collection class module named Employees,as described later in this chapter. Give the SmallBusiness object a read-only property of the Employees class.

Creating your own collection class: gives you the robustness of encapsulation,and as a bonus you get back the ability to use For Each … Next.

(3) Important In order for your collection classes to work with For Each … Next,you must provide a hidden NewEnum method with the correct procedure ID.

' NewEnum must return the IUnknown interface of a
' collection's enumerator.
Public Function NewEnum() As IUnknown
Set NewEnum = mcolEmployees . [ _NewEnum ]
End Function

The important thing you're delegating to the Collection object is its enumerator. An enumerator is a small object that knows how to iterate through the items in a collection.

The square brackets around the Collection object's _NewEnum method are necessary because of the leading underscore in the method name. This leading underscore is a convention indicating that the method is hidden in the type library.

You can't name your method _NewEnum,but you can hide it in the type library and give it the procedure ID(-4) that For Each … Next requires.

(4) Steps to Implement a Collection Class:

a) Add a class module to your project,and give it a name — usually the plural of the name of the object the collection class will contain.

b) Add a private variable to contain a reference to the Collection object your properties and methods will delegate to.

c) In the Class_Initialize event procedure,create the Collection object.

d) Add a Count property and Add,Item,and Remove methods to your class module; in each case,delegate to the private Collection by calling its corresponding member.

e) When you implement the Add method,you can override the behavior of the Collection object's undiscriminating Add method by accepting only objects of one type.

f) Use the Procedure Attributes dialog box to make the Item method the default for your collection class.

g) Add a NewEnum method,as shown below. Use the Procedure Attributes dialog box to mark it as hidden,and to give it a Procedure ID of –4 so that it will work with For Each … Next.

Public Function NewEnum() As IUnknown
Set NewEnum = mcol . [ _NewEnum ]
End Function

Note The code above assumes that the private variable in step 2 is named mcol.

h) Add custom properties,methods,and events to the collection class.

Note The Class Builder utility,included in the Professional and Enterprise editions of Visual Basic,will create collection classes for you. You can customize the resulting source code.

4. ActiveX Designers

(1) A designer provides a visual design window in the Visual Basic development environment. You can use this window to design new classes visually.

Objects created from the classes you design in this fashion have separate design-time and run-time behavior and appearance,although many objects — such as forms and controls — look very similar in the two modes.

(2) Difference between ActiveX Designer Classes to ActiveX controls:

  • If an object created from an ActiveX designer class is visible at run time,it has its own window. It is not contained within another form,as ActiveX controls are.
  • Like form classes,but unlike ActiveX controls,the classes produced by ActiveX designers are private classes. You cannot declare public methods that use these classes as argument types or return types.
  • Public Function A() As UseConnection1 'Error
    Public Sub B( CallBack As UseConnection1) 'Error

    (3) Creating ActiveX Designers: You can use the ActiveX Designer Software Development Kit to create new ActiveX designers for use with Visual Basic.

    Note The ActiveX Designer SDK requires a C++ compiler,such as Microsoft Visual C++. ActiveX designers cannot be written using Visual Basic.

    (4) Adding an ActiveX Designer to the Project Menu: Project->Components->Designers

    (5) Like all designers,the Microsoft Forms designer has its own run-time .dll. Using this designer in a Visual Basic project will therefore increase the memory requirements of the resulting executable.

    (6) Inserting a New Instance of an ActiveX Designer: On the Project menu,click Add designer (where designer is the name of the designer) to display a list of installed designers. Pick the designer you want from the list.

    (7) ActiveX Designers and SourceCode Control: When attempting to edit a file created by a designer,you may not be prompted to check out the file before editing. Additionally,some designers write files out to the file system; SourceCode control may not be aware of these files.

    版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

    相关推荐


    Format[$] ( expr [ , fmt ] ) format 返回变体型 format$ 强制返回为文本 -------------------------------- 数字类型的格式化 --------------------------------     固定格式参数:     General Number 普通数字,如可以用来去掉千位分隔号     format$("100,1
    VB6或者ASP 格式化时间为 MM/dd/yyyy 格式,竟然没有好的办法, Format 或者FormatDateTime 竟然结果和系统设置的区域语言的日期和时间格式相关。意思是尽管你用诸如 Format(Now, "MM/dd/yyyy"),如果系统的设置格式区域语言的日期和时间格式分隔符是"-",那他还会显示为 MM-dd-yyyy     只有拼凑: <%response.write
    在项目中添加如下代码:新建窗口来显示异常信息。 Namespace My ‘全局错误处理,新的解决方案直接添加本ApplicationEvents.vb 到工程即可 ‘添加后还需要一个From用来显示错误。如果到这步还不会则需要先打好基础啦 ‘======================================================== ‘以下事件
    转了这一篇文章,原来一直想用C#做k3的插件开发,vb没有C#用的爽呀,这篇文章写与2011年,看来我以前没有认真去找这个方法呀。 https://blog.csdn.net/chzjxgd/article/details/6176325 金蝶K3 BOS的插件官方是用VB6编写的,如果  能用.Net下的语言工具开发BOS插件是一件很愉快的事情,其中缘由不言而喻,而本文则是个人首创,实现在了用V
    Sub 分列() ‘以空格为分隔符,连续空格只算1个。对所选中的单元格进行处理 Dim m As Range, tmpStr As String, s As String Dim x As Integer, y As Integer, subStr As String If MsgBox("确定要分列处理吗?请确定分列的数据会覆盖它后面的单元格!", _
      窗体代码 1 Private Sub Text1_OLEDragDrop(Data As DataObject, Effect As Long, Button As Integer, Shift As Integer, X As Single, Y As Single) 2 Dim path As String, hash As String 3 For Each fil
      Imports MySql.Data.MySqlClient Public Class Form1 ‘ GLOBAL DECLARATIONS Dim conString As String = "Server=localhost;Database=net2;Uid=root;Pwd=123456;" Dim con As New MySqlConnection
    ‘導入命名空間 Imports ADODB Imports Microsoft.Office.Interop   Private Sub A1() Dim Sql As String Dim Cnn As New ADODB.Connection Dim Rs As New ADODB.Recordset Dim S As String   S = "Provider=OraOLEDB.Oracl
    Imports System.IO Imports System.Threading Imports System.Diagnostics Public Class Form1 Dim A(254) As String    Function ping(ByVal IP As Integer) As String Dim IPAddress As String IPAddress = "10.0.
    VB运行EXE程序,并等待其运行结束 参考:https://blog.csdn.net/useway/article/details/5494084 Private Declare Function WaitForSingleObject Lib "kernel32" (ByVal hHandle As Long, ByVal dwMilliseconds As Long) As Long Pr
    今天碰到一个问题,登陆的时候,如果不需要验证手机号为空,则不去验证手机号 因为登陆的时候所有的验证信息都存放在一个数组里 Dim CheckUserInfo() As String ={UserBirthday, SecEmail, UserMob, UserSex, RealNameFirst, RealName, CheckCardID, CheckCardType, Contactemail
    在VB6.0中,数据访问接口有三种: 1、ActiveX数据对象(ADO) 2、远程数据对象(RDO) 3、数据访问对象(DAO) 1.使用ADO(ActiveX Data Objec,ActiveX数据对象)连接SQL Server 1)使用ADO控件连接 使用ADO控件的ConnectionString属性就可以连接SQL Server,该属性包含一个由分号分隔的argument=value语
    注:大家如果没有VB6.0的安装文件,可自行百度一下下载,一般文件大小在200M左右的均为完整版的软件,可以使用。   特别提示:安装此软件的时候最好退出360杀毒软件(包括360安全卫士,电脑管家等,如果电脑上有这些软件的话),因为现如今的360杀毒软件直接会对VB6.0软件误报,这样的话就可能会在安装过程中被误报阻止而导致安装失败,或者是安装后缺乏很多必须的组件(其它的杀毒软件或安全卫士之类的
    Private Sub Form_Load() Call conndb End Sub Private Function conndb() Dim cn As New ADODB.Connection Dim rs As New ADODB.Recordset Dim strCn, sql As String Dim db_host As String Dim db_user As String
      PPSM06S70:  Add  moddate  EDITSPRINTJOB:  MAX(TO_CHAR(ETRN.MODDATE, ‘yyyy/mm/dd/HH24:MI AM‘)) ACTUAL_SHIPDATE   4.Test Scenario (1) :Query SQL Test DN:8016578337 SELECT CTRN.TKCTID TRUCK_ID,        
      沒有出現CrystalReportViewer時,須安裝CRforVS_13_0. 新增1個數據集,新增1個數據表,添加二列,列名要和資料庫名一樣. 修改目標Framework 修改app.config, <startup >改成<startup useLegacyV2RuntimeActivationPolicy ="true">  CrystalReport1.rpt增加數據庫專家 在表單
    Imports System.Threading Imports System Public Class Form1 Dim th1, th2 As Thread Public Sub Method1() Dim i As Integer For i = 1 To 100 If Me.Label1.BackColor =
    Friend Const PROCESS_ALL_ACCESS = &H1F0FFF = 2035711 Friend Const PROCESS_VM_READ = &H10 Friend Const PROCESS_VM_WRITE = &H20 Friend Const PAGE_READONLY = &H2 Friend Const PAGE_READWRITE = &H4 Friend
    以下代码随手写的 并没有大量测试 效率也有待提升 如果需要C#的请自行转换 Function SplitBytes(Data As Byte(), Delimiter As Byte()) As List(Of Byte()) Dim i = 0 Dim List As New List(Of Byte()) Dim bytes As New
    Imports System.Data.SqlClient Public Class Form1 REM Public conn1 As SqlConnection = New SqlConnection("server=.; Integrated Security=False;Initial Catalog= mydatabase1; User ID= sa;password")