编辑: 我希望在这里完成的三件主要事情是:
- 能够将属性/方法封装到类中(足够简单)
- 使用 Excel 范围作为用户输入,以便用户操作类属性值。
- (奖励)将用户更改发送回数据库。
我一直在考虑在 vba 中构建一些东西,让我可以将对象的属性绑定(bind)到 Range。基本上将单元格变成了绑定(bind)控件。
我可能需要的一些基本要求包括:
- 更改对象属性将更新单元格值
- 对单元格的更改将更新对象属性
- 可以绑定(bind)/取消绑定(bind)对象属性,而不会丢失属性的值。
我最初的想法是构建一个 BindRange
类,该类只需从一个范围中获取其值并将其值设置为该范围。
BindRange.cls:
Option Explicit
Private p_BoundCell As Range
Public Property Get Value() As String
If Me.IsBound Then Value = p_BoundCell.Value
End Property
Public Property Let Value(Val As String)
If Me.IsBound Then p_BoundCell.Value = Val
End Property
Public Property Get IsBound() As Boolean
If BoundToDeletedCell Then
Set p_BoundCell = Nothing
End If
IsBound = Not (p_BoundCell Is Nothing)
End Property
Public Sub Bind(Cell As Range)
Set p_BoundCell = Cell(1, 1)
End Sub
Private Function BoundToDeletedCell() As Boolean
Dim sTestAddress As String
On Error Resume Next
TRY:
If p_BoundCell Is Nothing Then
Exit Function
'// returns false
End If
sTestAddress = p_BoundCell.Address
If Err.Number = 424 Then 'object required
BoundToDeletedCell = True
End If
End Function
然后,我可以使用一对字段设置自定义对象来管理更新。我还需要一种方法来公开设置要绑定(bind)的范围。
测试对象.cls:
Option Explicit
Private p_BindId As BindRange
Private p_Id As String
Public Property Get Id() As String
If p_BindId.IsBound Then
p_Id = p_BindId.Value
End If
Id = p_Id
End Property
Public Property Let Id(Val As String)
p_Id = Val
If p_BindId.IsBound Then
p_BindId.Value = p_Id
End If
End Property
Public Sub Id_Bind(Cell As Range)
p_BindId.Bind Cell
End Sub
Private Sub Class_Initialize()
Set p_BindId = New BindRange
End Sub
Private Sub Class_Terminate()
Set p_BindId = Nothing
End Sub
这可能很烦人,因为我想要使任何属性“可绑定(bind)”,我必须为每个属性管理获取/设置和绑定(bind)。我也不太确定这是否会导致任何内存问题:使用变体类型值制作类属性....
还考虑构建一个类似服务的类,在类似字典的结构中跟踪对象及其边界范围?
无论如何,只是好奇是否有人以前做过类似的事情,或者您对如何设计它有任何想法。
最佳答案
将单个单元格绑定(bind)到属性会非常麻烦。我认为更好的技术是创建一个表作为属性表和一个引发 PropertyChange
事件的 PropertySheetWatcher
。
举例来说,我们想在名为 Stack OverKill 的用户窗体上创建一个简单的游戏。我们的游戏将有英雄类别和多个敌人类别(例如海龟、犀牛、狼)。尽管每个类都有自己的业务逻辑,但它们都共享公共(public)属性(名称、HP、ClassName、Left、Right ...等)。当然,由于它们都确保相同的基本属性集,因此它们都应该实现一个通用接口(interface)(例如 CharacterInterface
)。这样做的好处是它们都可以共享相同的属性表。
模拟属性表
PropertySheetWatcher:类
Private WithEvents ws As Worksheet
Public Table As ListObject
Public Event PropertyChange(ByVal PropertyName As String, Value As Variant)
Public Sub Init(ByRef PropertySheetTable As ListObject)
Set ws = PropertySheetTable.Parent
Set Table = PropertySheetTable
End Sub
Private Sub ws_Change(ByVal Target As Range)
Dim PropertyName As String
If Not Intersect(Target, Table.DataBodyRange) Then
PropertyName = Intersect(Target.EntireColumn, Table.HeaderRowRange).Value
RaiseEvent PropertyChange(PropertyName, Target.Value)
End If
End Sub
Public Sub UpdateProperty(ByVal PropertyName As String, Name As String, Value As Variant)
Application.EnableEvents = False
Dim RowIndex As Long
RowIndex = Table.ListColumns("Name").DataBodyRange.Find(Name).Row
Table.ListColumns(PropertyName).DataBodyRange.Cells(RowIndex).Value = Value
Application.EnableEvents = True
End Sub
英雄:职业
Implements CharacterInterface
Private Type Members
Name As String
HP As Single
ClassName As String
Left As Single
Right As Single
Top As Single
Bottom As Single
Direction As Long
Speed As Single
End Type
Private m As Members
Public WithEvents Watcher As PropertySheetWatcher
Private Sub Watcher_PropertyChange(ByVal PropertyName As String, Value As Variant)
Select Case PropertyName
Case "Speed"
Speed = Value
Case "HP"
'....More Code
End Select
End Sub
Public Property Get Speed() As Single
Speed = m.Speed
End Property
Public Property Let Speed(ByVal Value As Single)
m.Speed = Speed
Watcher.UpdateProperty "Speed", m.Name, Value
End Property
Private Property Get CharacterInterface_Speed() As Single
CharacterInterface_Speed = Speed
End Property
Private Property Let CharacterInterface_Speed(ByVal Value As Single)
Speed = Value
End Property
上面的类是通知系统如何实现的快速困惑。但等等,还有更多!!!
看看设置一个工厂来根据保存的设置重现所有角色是多么容易。
角色工厂:类
Function AddCharacters(Watcher As PropertySheetWatcher) As CharacterInterface
Dim Table As ListObject
Dim data As Variant
Dim RowIndex As Long
With Table
data = .DataBodyRange.Value
For RowIndex = 1 To UBound(data)
Select Case data(RowIndex, .ListColumns("Class").Index)
Case "Hero"
Set AddCharacters = AddCharacter(New Hero, Table, RowIndex)
Case "Turtle"
Set AddCharacters = AddCharacter(New Turtle, Table, RowIndex)
Case "Rhino"
Set AddCharacters = AddCharacter(New Rhino, Table, RowIndex)
Case "Wolf"
Set AddCharacters = AddCharacter(New Wolf, Table, RowIndex)
End Select
Next
End With
End Function
Private Function AddCharacter(Character As CharacterInterface, Table As ListObject, RowIndex As Long) As Object
With Character
.Speed = Table.ListColumns("Speed").DataBodyRange.Cells(RowIndex).Value
'....More Coe
End With
Set AddCharacter = Character
End Function
看起来我写了很多原创内容,但我没有。整个设置是对不同流行设计模式概念的改编。
关于excel - 将对象属性绑定(bind)到工作表单元格的技术,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57045213/