excel - 将对象属性绑定(bind)到工作表单元格的技术

标签 excel vba

编辑: 我希望在这里完成的三件主要事情是:

  • 能够将属性/方法封装到类中(足够简单)
  • 使用 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)。这样做的好处是它们都可以共享相同的属性表。

模拟属性表

Property Sheet Table Image

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/

相关文章:

vba - 工作表更改事件

vba - 将动态参数传递给 VBA 中的 Application.Run - 错误 449 参数不是可选错误

VBA:用于跨表操作的奇怪的慢宏(7k 行需要 15 分钟!)

python - 类型错误 : '_Folders' object is not callable

regex - 在 Excel 单元格中调用正则表达式

excel - 根据多列中的单元格查找匹配行值的公式

excel - 如何使用 Excel VBA 从 Outlook 检索电子邮件?

ms-access - TransferText 导出到 CSV 不起作用,但 TransferSpreadsheet 到 XLSX 起作用

excel - Application.Run 和范围参数?

excel - 对象变量或 with block 未设置 -