当值为null时,访问自定义属性的值会出现“Out of Memory”错误

时间:2012-11-06 00:36:09

标签: excel vba excel-vba

我正在尝试在工作表中创建自定义属性,然后检索其值。当我不使用空字符串,即""时,这很好。当我使用空字符串时,我收到此错误:

Run-time error '7':
Out of memory

这是我正在使用的代码:

Sub proptest()

Dim cprop As CustomProperty
Dim sht As Worksheet

Set sht = ThisWorkbook.Sheets("control")
sht.CustomProperties.Add "path", ""

For Each cprop In ThisWorkbook.Sheets("control").CustomProperties
    If cprop.Name = "path" Then
        Debug.Print cprop.Value
    End If
Next

End Sub

代码在Debug.Print cprop.value处失败。我不应该最初能够将属性设置为""吗?

4 个答案:

答案 0 :(得分:1)

使用 vbNullChar 可以使用,示例:

Sub proptest()
  Dim sht As Worksheet
  Set sht = ThisWorkbook.Sheets("control")

  ' On Error Resume Next
  sht.CustomProperties.Item(1).Delete
  ' On Error GoTo 0

  Dim pathValue As Variant
  pathValue = vbNullChar

  Dim pathCustomProperty As CustomProperty
  Set pathCustomProperty = sht.CustomProperties.Add("path", pathValue)

  Dim cprop As CustomProperty
  For Each cprop In ThisWorkbook.Sheets("control").CustomProperties
      If cprop.Name = "path" Then
          Debug.Print cprop.Value
      End If
  Next

End Sub

答案 1 :(得分:1)

我认为丹尼尔·杜塞克的评论和答案显然无法做到这一点。该属性应至少有1个字符有效,空字符串不允许,并且在调用.Value时会出错。

因此,当您没有为其分配实际值时,Add此属性的长度为1或更多string并且您Delete属性。

答案 2 :(得分:0)

如前所述,无法设置空字符串。

一个简单的解决方法是使用一个神奇的单词或字符,例如~Empty(或任何足以证明您的能力的东西):

Dim MyProperty As Excel.CustomProperty = ...
Dim PropertyValue As String = If(MyProperty.Value = "~Empty", String.Empty, MyPropertyValue)

一种稍微昂贵一点的解决方法,但100%安全是使用一个字符开始的自定义属性的所有值,然后始终将其删除。访问该值时,系统地删除第一个字符:

Dim MyProperty As Excel.CustomProperty = ...
Dim PropertyValue As String = Strings.Mid(MyProperty.Value, 2)

您可以编写一个扩展名以使您的生活更轻松:

<System.Runtime.CompilerServices.Extension>
Function ValueTrim(MyProperty as Excel.CustomProperty) As String
    Return Strings.Mid(MyProperty.Value, 2)
End Function

现在您可以像这样使用它:Dim MyValue As String = MyProperty.ValueTrim

添加自定义属性时,请遵循相反的原则:

<System.Runtime.CompilerServices.Extension>
Function AddTrim(MyProperties As Excel.CustomProperties, Name As String, Value As String) as Excel.CustomProperty
    Dim ModifiedValue As String = String.Concat("~", Value) 'Use ~ or whatever character you lie / Note Strig.Concat is the least expensive way to join two strings together.
    Dim NewProperty As Excel.CustomProperty = MyProperties.Add(Name, ModifiedValue)      
    Return NewProperty 
End Function

要像这样使用:MyProperties.AddTrim(Name, Value)

希望这可以帮助遇到此问题的其他人。

答案 3 :(得分:0)

根据其他答案和一些反复试验,我编写了一个类来包装 Worksheet.CustomProperty

工作表属性:类

设置和获取 Worksheet.CustomProperty 的值并测试 Worksheet 是否具有 CustomProperty

VERSION 1.0 CLASS
Attribute VB_Name = "WorksheetProperty"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = True
Attribute VB_Exposed = False
'@Folder("Classes")
'@PredeclaredId

Option Explicit
Private Type TMembers
    Name As String
    Worksheet As Worksheet
End Type
Private this As TMembers

Public Property Get Create(pWorksheet As Worksheet, pName As String) As WorksheetProperty
    With New WorksheetProperty
        Set .Worksheet = pWorksheet
        .Name = pName
        Set Create = .Self
    End With
End Property

Public Property Get Self() As WorksheetProperty
    Set Self = Me
End Property

Public Property Get Worksheet() As Worksheet
    Set Worksheet = this.Worksheet
End Property

Public Property Set Worksheet(ByVal pValue As Worksheet)
    Set this.Worksheet = pValue
End Property

Public Property Get Name() As String
    Name = this.Name
End Property

Public Property Let Name(ByVal pValue As String)
    this.Name = pValue
End Property

Public Property Get Value() As String
    Dim P As CustomProperty
    For Each P In Worksheet.CustomProperties
        If P.Name = Name Then
            Value = P.Value
            Exit Property
        End If
    Next
End Property

Public Property Let Value(ByVal pValue As String)
    Delete
    Worksheet.CustomProperties.Add Name:=Name, Value:=pValue
End Property

Public Property Get hasCustomProperty(pWorksheet As Worksheet, pName As String) As Boolean
    Dim P As CustomProperty
    For Each P In pWorksheet.CustomProperties
        If P.Name = pName Then
            hasCustomProperty = True
            Exit Property
        End If
    Next
End Property


Public Sub Delete()
     Dim P As CustomProperty
    For Each P In Worksheet.CustomProperties
        If P.Name = Name Then
            P.Delete
            Exit For
        End If
    Next
End Sub

用法

我的自定义 Unit 类有几个属性返回一个 WorksheetProperty。它使我的数据库与我的工作表同步变得非常容易。

Public Function hasMeta(Ws As Worksheet) As Boolean
    hasMeta = WorksheetProperty.hasCustomProperty(Ws, MetaName)
End Function

Public Property Get Id() As WorksheetProperty
    Set Id = WorksheetProperty.Create(this.Worksheet, "id")
End Property

Public Property Get CourseID() As WorksheetProperty
    Set CourseID = WorksheetProperty.Create(this.Worksheet, "course_id")
End Property

Public Property Get Name() As WorksheetProperty
    Set Name = WorksheetProperty.Create(this.Worksheet, "unit_name")
End Property

简单使用

'ActiveSheet has a CustomProperty
Debug.Print WorksheetProperty.hasCustomProperty(ActiveSheet, "LastDateSynced")

'Set a CustomProperty
WorksheetProperty.Create(ActiveSheet, "LastDateSynced").Value = Now

'Retrieve a CustomProperty
Debug.Print WorksheetProperty.Create(ActiveSheet, "LastDateSynced").Value