How can I revert a property to its default value? - vb.net

Public Property Name() As String = "default_name"
Sub InitializeFields()
Name = String.Empty
'
'
'
Name = Name.GetDefaultValue.ToString ' an example
End Sub
Programmatically, how can I revert the default value "default_name" of any property?

Here's an example of how you ought to do this with an actual default value:
Imports System.ComponentModel
Public Class Thing
<DefaultValue("Hello World")>
Public Property WithDefault As String
Public Property WithoutDefault As String
End Class
Imports System.ComponentModel
Imports System.Reflection
Module Module1
Sub Main()
Dim something As New Thing
something.WithDefault = "First"
something.WithoutDefault = "Second"
If TrySetDefaultValue(something, NameOf(something.WithDefault)) Then
Console.WriteLine($"{NameOf(something.WithDefault)} reset to ""{something.WithDefault}""")
Else
Console.WriteLine($"No default value for {NameOf(something.WithDefault)}")
End If
If TrySetDefaultValue(something, NameOf(something.WithoutDefault)) Then
Console.WriteLine($"{NameOf(something.WithoutDefault)} reset to ""{something.WithoutDefault}""")
Else
Console.WriteLine($"No default value for {NameOf(something.WithoutDefault)}")
End If
End Sub
Public Function TryGetDefaultValue([object] As Object, propertyName As String, ByRef value As Object) As Boolean
Dim attribute = [object].GetType().GetProperty(propertyName).GetCustomAttribute(Of DefaultValueAttribute)()
If attribute Is Nothing Then
Return False
End If
value = attribute.Value
Return True
End Function
Public Function TrySetDefaultValue([object] As Object, propertyName As String) As Boolean
Dim [property] = [object].GetType().GetProperty(propertyName)
Dim attribute = [property].GetCustomAttribute(Of DefaultValueAttribute)()
If attribute Is Nothing Then
Return False
End If
Dim value = attribute.Value
[property].SetValue([object], value)
Return True
End Function
End Module

There's no out-of-the-box way to somehow revert a property to its (custom) initial value. Once it's changed, it's over; the original value is lost.
Assuming the property belongs to a class (and that it doesn't get modified in the constructor), you could retrieve the value by creating a temporary instance of the class. For example:
Class SomeClass
Public Property Name As String = "default_name"
Sub InitializeFields()
Name = String.Empty
'
'
'
Name = New SomeClass().Name
End Sub
End Class
However, that's not very robust and could get ugly really fast. The way I would do this is by storing the default value in a constant:
Private Const DefaultName As String = "default_name"
Public Property Name As String = DefaultName
Sub InitializeFields()
Name = String.Empty
'
'
'
Name = DefaultName
End Sub
And then you can do that for each property that you need to later access its original value.

Answering myself:
Imports System.Reflection
Imports System.ComponentModel
Public Class clsThisClass
' each property have attribute of default value
<DefaultValue(0)>
Public Property RecordCount() As Long = 0
<DefaultValue("a")>
Public Property SQL() As String = String.Empty
<DefaultValue(0)>
Public Property IndexID() As Long = 0
<DefaultValue("b")>
Public Property Name() As String = String.Empty
<DefaultValue("c")>
Public Property Title() As String = String.Empty
<DefaultValue("d")>
Public Property Document_No() As String = String.Empty
<DefaultValue("abc")>
Public Property Company_Code() As String = String.Empty
Sub InitializeFields()
With Me
RecordCount = 28
IndexID = 10
Name = "name"
Title = "title"
Document_No = "doc_no"
Company_Code = "com_code"
Debug.WriteLine(RecordCount)
Debug.WriteLine(IndexID)
Debug.WriteLine(Name)
Debug.WriteLine(Document_No)
Debug.WriteLine(Company_Code)
' revert or reset all properties to default value upon initialization
Dim aType As Type = GetType(clsThisClass)
' each property of class
For Each pi As System.Reflection.PropertyInfo In aType.GetProperties()
' grab assigned default value of the property
Dim attribute = Me.GetType().GetProperty(pi.Name.ToString).GetCustomAttribute(Of DefaultValueAttribute)()
Try
Dim value As Object = Nothing
' convert value type according to the type of the property
value = CTypeDynamic(value, GetType(Attribute))
If Not attribute Is Nothing Then
value = attribute.Value
' set default value
pi.SetValue(Me, value)
End If
Catch ex As Exception
End Try
Next
Debug.WriteLine(RecordCount)
Debug.WriteLine(IndexID)
Debug.WriteLine(Name)
Debug.WriteLine(Document_No)
Debug.WriteLine(Company_Code)
End With
End Sub
End Class
Output:
28
10
name
doc_no
com_code
0
0
a
b
c
d
abc
initialized all properties with a default value at once.
in my scenario, I have numerous classes and have several properties.
by doing these few lines of code. I can copy-paste in each class at initializing method. it saved lots of time for writing code.

Related

Casting from class to interface in Excel VBA

In Excel 2013, I have two classes: LoadCase and LoadCombination, which implement interface ILoadCase.
The declaration for ILoadCase is:
Option Explicit
'' Public properties
Public Property Get Name() As String
End Property
Public Property Let Name(ByVal value As String)
End Property
Public Property Get ID() As Long
End Property
Public Property Let ID(ByVal valus As Long)
End Property
And the (partial) implementations for both LoadCase and LoadCombination are:
Option Explicit
Implements ILoadCase
'' Public properties
Public Property Get ILoadCase_Name() As String
ILoadCase_Name = pName
End Property
Private Property Let ILoadCase_Name(ByVal value As String)
pName = value
End Property
Public Property Get ILoadCase_ID() As Long
ILoadCase_ID = pID
End Property
Private Property Let ILoadCase_ID(ByVal value As Long)
pID = value
End Property
I've omitted code which is irrelevant to the implementation of the interface.
I then have a class BeamForces, which contains results for a particular ILoadCase object:
Option Explicit
Public Fx As Double
Public Fy As Double
Public Fz As Double
Public Mx As Double
Public My As Double
Public Mz As Double
Public ParentLoadCase As ILoadCase
I thought that with this I'd be able to do something like this:
Set currentBeamForces = New BeamForces
With currentBeamForces
.Fx = forces(0)
.Fy = forces(1)
.Fz = forces(2)
.Mx = forces(3)
.My = forces(4)
.Mz = forces(5)
Set .ParentLoadCase = TargetLoadCase
End With
Where TargetLoadCase is either a LoadCase or a LoadCombination, but this gives me an error every time.
I've coded this like I would in .NET and just expected that it would work, but does casting to an interface not work in VBA? Or am I going wrong here somewhere?
EDIT
More details. I first call the following method:
Public Function LoadBeamForcesAtNode(ByVal TargetBeam As Beam, ByVal TargetNode As Node, Optional ByVal TargetLoadCases As Collection = Nothing) As Boolean
Dim i As Integer
Dim currentLoadCase As Variant
Dim targetBeamForces As BeamForces
If TargetLoadCases Is Nothing Then
For Each currentLoadCase In Me.LoadCases.Items
Call TargetLoadCases.Add(currentLoadCase)
Next
For Each currentLoadCase In Me.LoadCombinations.Items
Call TargetLoadCases.Add(currentLoadCase)
Next
End If
'On Error GoTo ExitPoint
For Each currentLoadCase In TargetLoadCases
Set targetBeamForces = InstantiateBeamForces(TargetBeam, TargetNode, currentLoadCase)
If TargetNode Is TargetBeam.Node1 Then
Set TargetBeam.Forces1 = targetBeamForces
Else
Set TargetBeam.Forces2 = targetBeamForces
End If
Next
LoadBeamForcesAtNode = True
ExitPoint:
End Function
Where TargetLoadCases is a collection which can contain both LoadCase and LoadCombination objects.
The problem occurs in InstantiateBeamForces, the code for which is
Private Function InstantiateBeamForces(ByVal TargetBeam As Beam, ByVal TargetNode As Node, ByVal TargetLoadCase As Variant) As BeamForces
Dim forces(5) As Double
Dim currentBeamForces As BeamForces
Call Me.output.GetMemberEndForces(TargetBeam.ID, IIf(TargetNode Is TargetBeam.Node1, 0, 1), TargetLoadCase.ILoadCase_ID, forces, 0)
Set currentBeamForces = New BeamForces
With currentBeamForces
.Fx = forces(0)
.Fy = forces(1)
.Fz = forces(2)
.Mx = forces(3)
.My = forces(4)
.Mz = forces(5)
Set .ParentLoadCase = TargetLoadCase
End With
Set InstantiateBeamForces = currentBeamForces
End Function
Which creates a new BeamForces object and populates it with the values returned by the ...GetMemberEndForces(...) API COM call.
The problem is that the .ParentLoadCase property is nothing after the assignment, so I'm assuming an invalid cast...
** EDIT 2 **
Here is a screenshot of TargetLoadCase when I put a breakpoint in InstantiateBeamForces.
The ILoadCase member is Nothing, but I don't get why. Could this be the cause of the problem?

How to create a compound object in VBA?

I cannot make my way through the Microsoft help, which is great provided you know what the answer is already, so I'm stuck.
Is it possible for me to create my own compound object (I assume that this is the term) such that, for example, the object could be a person and would have the following sub-classes:
Firstname - String
Surname - String
Date of birth - Datetime
Gender - String (M/F accepted)
Height - Real number
Sorry if it seems like a very basic question (no pun intended) but I haven't used Visual Basic for a long time, and Microsoft Visual Basic was never my forté.
You should consider using class modules instead of types. Types are fine, but they're limited in what they can do. I usually end up converting my types to classes as soon as I need some more function than a type can provide.
You could create a CPerson class with the properties you want. Now if you want to return a FullName property, you can write a Property Get to return it - something you can't do with a type.
Private mlPersonID As Long
Private msFirstName As String
Private msSurname As String
Private mdtDOB As Date
Private msGender As String
Private mdHeight As Double
Private mlParentPtr As Long
Public Property Let PersonID(ByVal lPersonID As Long): mlPersonID = lPersonID: End Property
Public Property Get PersonID() As Long: PersonID = mlPersonID: End Property
Public Property Let FirstName(ByVal sFirstName As String): msFirstName = sFirstName: End Property
Public Property Get FirstName() As String: FirstName = msFirstName: End Property
Public Property Let Surname(ByVal sSurname As String): msSurname = sSurname: End Property
Public Property Get Surname() As String: Surname = msSurname: End Property
Public Property Let DOB(ByVal dtDOB As Date): mdtDOB = dtDOB: End Property
Public Property Get DOB() As Date: DOB = mdtDOB: End Property
Public Property Let Gender(ByVal sGender As String): msGender = sGender: End Property
Public Property Get Gender() As String: Gender = msGender: End Property
Public Property Let Height(ByVal dHeight As Double): mdHeight = dHeight: End Property
Public Property Get Height() As Double: Height = mdHeight: End Property
Public Property Get FullName() As String
FullName = Me.FirstName & Space(1) & Me.Surname
End Property
Then you can create a CPeople class to hold all of your CPerson instances.
Private mcolPeople As Collection
Private Sub Class_Initialize()
Set mcolPeople = New Collection
End Sub
Private Sub Class_Terminate()
Set mcolPeople = Nothing
End Sub
Public Property Get NewEnum() As IUnknown
Set NewEnum = mcolPeople.[_NewEnum]
End Property
Public Sub Add(clsPerson As CPerson)
If clsPerson.PersonID = 0 Then
clsPerson.PersonID = Me.Count + 1
End If
mcolPeople.Add clsPerson, CStr(clsPerson.PersonID)
End Sub
Public Property Get Person(vItem As Variant) As CPerson
Set Person = mcolPeople.Item(vItem)
End Property
Public Property Get Count() As Long
Count = mcolPeople.Count
End Property
Public Property Get FilterByGender(ByVal sGender As String) As CPeople
Dim clsReturn As CPeople
Dim clsPerson As CPerson
Set clsReturn = New CPeople
For Each clsPerson In Me
If clsPerson.Gender = sGender Then
clsReturn.Add clsPerson
End If
Next clsPerson
Set FilterByGender = clsReturn
End Property
With this class, you can For Each through all the instances (google custom class and NewEnum to see how to do that). You can also use a Property Get to return a subset of the CPerson instances (females in this case).
Now in a standard module, you can create a couple of CPerson instances, add them to your CPeople instance, filter them, and loop through them.
Public Sub FillPeople()
Dim clsPerson As CPerson
Dim clsPeople As CPeople
Dim clsFemales As CPeople
Set clsPeople = New CPeople
Set clsPerson = New CPerson
With clsPerson
.FirstName = "Joe"
.Surname = "Blow"
.Gender = "M"
.Height = 72
.DOB = #1/1/1980#
End With
clsPeople.Add clsPerson
Set clsPerson = New CPerson
With clsPerson
.FirstName = "Jane"
.Surname = "Doe"
.Gender = "F"
.Height = 62
.DOB = #1/1/1979#
End With
clsPeople.Add clsPerson
Set clsFemales = clsPeople.FilterByGender("F")
For Each clsPerson In clsFemales
Debug.Print clsPerson.FullName
Next clsPerson
End Sub
There's defintely more learning curve to creating classes, but it's worth it in my opinion.
I think you need to use TYPE syntax, like this:
TYPE person
Firstname As String
Surname As String
Date_of_birth As Date ' instead of Datetime
Gender As String '(M/F accepted)
Height As Single 'instead of Real number
END TYPE
Sub Test()
Dim aTest As person
End Sub

Application-defined or object-defined error (VBA)

I keep getting the annoying error message: Application-defined or object-defined error (VBA).
Background: I have a worksheet that contains rows and columns (some rows & columns are merged), I have a button on the worksheet that I would like to use to validate the worksheet e.g. to report any errors if a cell is not filled in i.e. empty. In additions, I would like empty cells to become red when the button is clicked on an a particular range of cells contain no values.
I created a VBA Bean to hold all rows of data that are pulled from the worksheet. This class will contain procedures and/or functions that validate the class and hopefully report back to the user any errors encountered. The button calls the print_cheque_Click() (worksheet code below). Any suggestions here would be much appreciated. Thanks in advance.
line where error is occurring: Range(cCel).Interior.Color = RGB(255, 0, 0)
error
Public Sub validate()
Dim str As String
Dim cCel As String
Dim WS As Worksheet
Set WS = Worksheets("EFF_PAYROLL")
WS.Select
With Selection
If Me.getJournalYear = "" Then
cCel = Me.getJournalYearCell
**Range(cCel).Interior.Color = RGB(255, 0, 0)**
Else
**Range(cCel).Interior.Color = RGB(255, 255, 255)**
End If
End With
End Sub
class employee
Option Explicit
'****************************
'class definition of Employee
'VBA Bean
'****************************
'******************
'private Attributes
'******************
Private eID As Integer
Private jYear As String
Private jYearCell As String
Private eRegion As String
Private eRegionCell As String
Private eDistrict As String
Private eDistrictCell As String
Private eJournalNumber As String
Private eJournalNumberCell As String
Private eName As String
Private eNameCell As String
Private class_code As String
Private class_codeCell As String
Private hourly_rate As String
Private hourly_rateCell As String
Private eCertNumber As String
Private eCertNumberCell As String
Private eRegRate As String
Private eRegRateCell As String
Private eRegHours As String
Private eRegHoursCell As String
Private eOvertimeRate As String
Private eOvertimeRateCell As String
Private eOvertimeHours As String
Private eOvertimeHoursCell As String
Private eRegTotal As String
Private eRegTotalCell As String
Private eOvertimeTotal As String
Private eOvertimeTotalCell As String
Private eVacationTotal As String
Private eVacactionTotalCell As String
Private eTotalPay As String
Private eTotalPayCell As String
Private eCommissary As String
Private eCommissaryCell As String
Private eTotalCommissary As String
Private eTotalCommissaryCell As String
Private eNetPay As String
Private eNetPayCell As String
Private eDay As String
Private eDayCell As String
Private eMonth As String
Private eMonthCell As String
Private eYear As String
Private eYearCell As String
Private eChequeNo As String
Private eChequeNoCell As String
Private eAddress1 As String
Private eAddress1Cell As String
Private eAddress2 As String
Private eAddress2Cell As String
Private eAuthorizedOfficer As String
Private eAuthorizedOfficerCell As String
Private ePrintedName As String
Private ePrintedNameCell As String
Private ePreparedBy As String
Private ePreparedByCell As String
'***************
'Get/Set Methods
'***************
'*******************************************
'eID section
Public Property Get getID() As String
getID = eID
End Property
Public Property Let setID(value As String)
setID = value
End Property
'END eID section
'*******************************************
'journal year
Public Property Get getJournalYear() As String
getJournalYear = jYear
End Property
Public Property Let setJournalYear(value As String)
jYear = value
End Property
'end journal year
'setJournalYearCell
Public Property Get getJournalYearCell() As String
getJournalYearCell = jYearCell
End Property
Public Property Let setJournalYearCell(value As String)
jYearCell = value
End Property
'end setJournalYearCell
'class code
Public Property Get getClassCode() As String
getClassCode = class_code
End Property
Public Property Let setClassCode(value As String)
class_code = value
End Property
'end class code
'class code cell
Public Property Get getClassCodeCell() As String
getClassCodeCell = class_codeCell
End Property
Public Property Let setClassCodeCell(value As String)
class_codeCell = value
End Property
'end class code code cell
'hourly rate
Public Property Get getHourlyRate() As String
getHourlyRate = hourly_rate
End Property
Public Property Let setHourlyRate(value As String)
hourly_rate = value
End Property
'end hourly rate
'hourly rate cell
Public Property Get getHourlyRatCell() As String
getHourlyRateCell = hourly_rateCell
End Property
Public Property Let setHourlyRateCell(value As String)
hourly_rateCell = value
End Property
'end hourly rate cell
'chequeNo
Public Property Get getChequeNo() As String
getChequeNo = eChequeNo
End Property
Public Property Let setchequeNo(value As String)
eChequeNo = value
End Property
'end chequeNo
'chequeNoCell
Public Property Get getChequeNoCell() As String
getChequeNoCell = eChequeNoCell
End Property
Public Property Let setChequeNoCell(value As String)
eChequeNoCell = value
End Property
'end chequeCell
'prepredBy
Public Property Get getPreparedBy() As String
getPreparedBy = ePreparedBy
End Property
Public Property Let setPreparedBy(value As String)
ePreparedBy = value
End Property
'end preparedBy
'preparedByCell
Public Property Get getPreparedByCell() As String
getPreparedByCell = ePreparedByCell
End Property
Public Property Let setPreparedByCell(value As String)
ePreparedByCell = value
End Property
'end preparedByCell
'region
Public Property Get getRegion() As String
getRegion = eRegion
End Property
Public Property Let setRegion(value As String)
eRegion = value
End Property
'end region
'regionCell
Public Property Get getRegionCell() As String
getRegionCell = eRegionCell
End Property
Public Property Let setRegionCell(value As String)
eRegionCell = value
End Property
'end regionCell
'BEGIN
'district
Public Property Get getDistrict() As String
getDistrict = eDistrict
End Property
Public Property Let setDistrict(value As String)
eDistrict = value
End Property
'end district
'districtCell
Public Property Get getDistrictCell() As String
getDistrictCell = eDistrictCell
End Property
Public Property Let setDistrictCell(value As String)
eDistrictCell = value
End Property
'end districtCell
'eYear section
Public Property Get getYear() As String
getYear = eYear
End Property
Public Property Let setYear(value As String)
eYear = value
End Property
'END eYear Section
'eYearCell
Public Property Get getEYearCell() As String
getEYearCell = eYearCell
End Property
Public Property Let setEYearCell(value As String)
eYearCell = value
End Property
'end eYearCell
'eMonth section
Public Property Get getMonth() As String
getMonth = eMonth
End Property
Public Property Let setMonth(value As String)
eMonth = value
End Property
'END eMonth Section
'eMonthCell
Public Property Get getEMonthCell() As String
getEMonthCell = eMonthCell
End Property
Public Property Let setEMonthCell(value As String)
eMonthCell = value
End Property
'end eMonthCell
'eDay section
Public Property Get getDay() As String
getDay = eDay
End Property
Public Property Let setDay(value As String)
eDay = value
End Property
'END eDay Section
'eDayCell
Public Property Get getEDayCell() As String
getEDayCell = eDayCell
End Property
Public Property Let setEDayCell(value As String)
eDayCell = value
End Property
'end eDayCell
'eJournalNumber section
Public Property Get getJournalNumber() As String
getJournalNumber = eJournalNumber
End Property
Public Property Let setJournalNumber(value As String)
eJournalNumber = value
End Property
'end journal number
'eJournalNumberCell
Public Property Get getJournalNumberCell() As String
getJournalNumberCell = eJournalNumberCell
End Property
Public Property Let setJournalNumberCell(value As String)
eJournalNumberCell = value
End Property
'end eJournalNumberCell
'eName Section
Public Property Get getName() As String
getName = eName
End Property
Public Property Let setName(value As String)
eName = value
End Property
'END eName section
'eNameCell
Public Property Get getNameCell() As String
getNameCell = eNameCell
End Property
Public Property Let setNameCell(value As String)
eNameCell = value
End Property
'end eNameCell
'address1
Public Property Get getAddress1() As String
getAddress1 = eAddress1
End Property
Public Property Let setAddress1(value As String)
eAddress1 = value
End Property
'end address1
'adress1Cell
Public Property Get getAddress1Cell() As String
getAddress1Cell = eAddress1Cell
End Property
Public Property Let setAAddress1Cell(value As String)
eAddress1Cell = value
End Property
'end address1Cell
'address2
Public Property Get getAddress2() As String
getAddress2 = eAddress2
End Property
Public Property Let setAddress2(value As String)
eAddress2 = value
End Property
'end address2
'address2Cell
Public Property Get getAddress2Cell() As String
getAddress2Cell = eAddress2
End Property
Public Property Let setAddress2cell(value As String)
eAddress2Cell = value
End Property
'end address2Cell
'certNumber
Public Property Get getCertNumber() As String
getCertNumber = eCertNumber
End Property
Public Property Let setCertNumber(value As String)
eCertNumber = value
End Property
'end certNumber
'certNumberCell
Public Property Get getCertNumberCell() As String
getCertNumberCell = eCertNumberCell
End Property
Public Property Let setCertNumberCell(value As String)
eCertNumberCell = value
End Property
'end CertNumberCell
'regRate
Public Property Get getRegRate() As String
getRegRate = eRegRate
End Property
Public Property Let setRegRate(value As String)
eRegRate = value
End Property
'end regRate
'regRateCell
Public Property Get getRegRateCell() As String
getRegRateCell = eRegRateCell
End Property
Public Property Let setRegRateCell(value As String)
eRegRateCell = value
End Property
'end regRateCell
'regHours
Public Property Get getRegHours() As String
getRegHours = eRegHours
End Property
Public Property Let setRegHours(value As String)
eRegHours = value
End Property
'end regHours
'regHoursCell
Public Property Get getRegHoursCell() As String
getRegHours = eRegHoursCell
End Property
Public Property Let setRegHoursCell(value As String)
eRegHoursCell = value
End Property
'end regHoursCell
'overtimeRate
Public Property Get getOvertimeRate() As String
getOvertimeRate = eOvertimeRate
End Property
Public Property Let setOvertimeRate(value As String)
eOvertimeRate = value
End Property
'end overtimeRate
'overtimeRateCell
Public Property Get getOvertimeRateCell() As String
getOvertimeRateCell = eOvertimeRateCell
End Property
'end
Public Property Let setOvertimeRateCell(value As String)
eOvertimeRateCell = value
End Property
'end overtimeRateCell
'overtimeHours
Public Property Get getOvertimeHours() As String
getOvertimeHours = eOvertimeHours
End Property
Public Property Let setOvertimeHours(value As String)
eOvertimeHours = value
End Property
'end overtimeHours
'overtimeHoursCell
Public Property Get getOvertimeHoursCell() As String
getOvertimeHoursCell = eOvertimeHoursCell
End Property
Public Property Let setOvertimeHoursCell(value As String)
eOvertimeHoursCell = value
End Property
'end overtimeHoursCell
'regTotal
Public Property Get getRegTotal() As String
getRegTotal = eRegTotal
End Property
Public Property Let setRegTotal(value As String)
eRegTotal = value
End Property
'end regTotal
'regTotalCell
Public Property Get getRegTotalCell() As String
getRegTotalCell = eRegTotalCell
End Property
Public Property Let setRegTotalCell(value As String)
eRegTotalCell = value
End Property
'end regTotalCell
'overtimeTotal
Public Property Get getOvertimeTotal() As String
getOvertimeTotal = eOvertimeTotal
End Property
Public Property Let setOvertimeTotal(value As String)
eOvertimeTotal = value
End Property
'end overtimeTotal
'overtimeTotalCell
Public Property Get getOvertimeTotalCell() As String
getOvertimeTotalCell = eOvertimeTotalCell
End Property
Public Property Let setOvertimeTotalCell(value As String)
eOvertimeTotalCell = value
End Property
'end overtimeTotalCell
'vacationTotal
Public Property Get getVacationTotal() As String
getVacationTotal = eVacationTotal
End Property
Public Property Let setVacationTotal(value As String)
eVacationTotal = value
End Property
'end vacationTotal
'vacationTotalCell
Public Property Get getVacationTotalCell() As String
getVacationTotalCell = eVacationTotalCell
End Property
Public Property Let setVacationTotalCell(value As String)
eVacationTotalCell = value
End Property
'end vacationTotalCell
'totalPay
Public Property Get getTotalPay() As String
getTotalPay = eTotalPay
End Property
Public Property Let setTotalPay(value As String)
eTotalPay = value
End Property
'end totalPay
'totalPayCell
Public Property Get getTotalPayCell() As String
getTotalPayCell = eTotalPayCell
End Property
Public Property Let setTotalPayCell(value As String)
eTotalPayCell = value
End Property
'end totalPayCell
'revisit
'************ buffer issue ? ********************
'commissary
Public Property Get getCommissary() As String
getCommissary = eCommissary
End Property
Public Property Let setCommissary(value As String)
eCommissary = value
End Property
'end commissary
'commissary
Public Property Get getCommissaryCell() As String
getCommissaryCell = eCommissaryCell
End Property
Public Property Let setCommissaryCell(value As String)
eCommissaryCell = value
End Property
'end commissary
'totalCommissary
Public Property Get getTotalCommissary() As String
getTotalCommissary = eTotalCommissary
End Property
Public Property Let setTotalCommissary(value As String)
eTotalCommissary = value
End Property
'end totalCommissary
'totalCommissaryCell
Public Property Get getTotalCommissaryCell() As String
getTotalCommissaryCell = eTotalCommissary
End Property
Public Property Let setTotalCommissaryCell(value As String)
eTotalCommissaryCell = value
End Property
'end totalCommissaryCell
'netPay
Public Property Get getNetPay() As String
getNetPay = eNetPay
End Property
Public Property Let setNetPay(value As String)
eNetPay = value
End Property
'end netPay
'netPayCell
Public Property Get getNetPayCell() As String
getNetPayCell = eNetPayCell
End Property
Public Property Let setNetPayCell(value As String)
eNetPayCell = value
End Property
'end netPayCell
'authorizedOfficer
Public Property Get getAuthorizedOfficer() As String
getAuthorizedOfficer = eAuthorizedOfficer
End Property
Public Property Let setAuthorizedOfficer(value As String)
eAuthorizedOfficer = value
End Property
'end authorizedOfficer
'authorizedOfficerCell
Public Property Get getAuthorizedOfficerCell() As String
getAuthorizedOfficerCelll = eAuthorizedOfficerCell
End Property
Public Property Let setAuthorizedOfficerCell(value As String)
eAuthorizedOfficerCell = value
End Property
'end authorizedOfficer
'printedName
Public Property Get getPrintedName() As String
getPrintedName = ePrintedName
End Property
Public Property Let setPrintedName(value As String)
ePrintedName = value
End Property
'end printedName
'printedNameCell
Public Property Get getPrintedNameCell() As String
getPrintedNameCell = ePrintedNameCell
End Property
Public Property Let setPritnedNameCell(value As String)
ePrintedNameCell = value
End Property
'end printedNameCell
'***************
'Procedure / Function
'***************
Public Sub validate()
Dim str As String
Dim cCel As String
Dim WS As Worksheet
Set WS = Worksheets("EFF_PAYROLL")
WS.Select
With Selection
If Me.getJournalYear = "" Then
cCel = Me.getJournalYearCell
Range(cCel).Interior.Color = RGB(255, 0, 0)
Else
Range(cCel).Interior.Color = RGB(255, 255, 255)
End If
End With
End Sub
'constructor
Private Sub Class_Initialize()
'assign an ID to each new employee object
eID = eID + 1
End Sub
'end constructor
worksheet code
Private Sub print_cheque_Click()
Dim template As Worksheet
Dim rng As Range
Dim journal As Range
Dim iReply As Integer
Dim row As Range
Dim cell As Range
Dim employeeCollection As Collection
Set employeeCollection = New Collection
'EFF_PAYROLL fields
Dim dayStr As String
Dim monthStr As String
'boolean flag - if error is raised don't print cheque
Dim errorFlag As Boolean
errorFlag = True 'raise error if no fields are filled in
Dim str As String
'*************************
'work with Employee Object
'*************************
'find the number of cheques to be created by cheque number
Set rng = Sheets("EFF_PAYROLL").Range("a7:a35")
'define employee object
Dim emp As employee
'********local variables **********
'**********************************
Dim year As String
Dim cell_address As String
Dim name As String
For Each row In rng.Rows
'create new employee foreach row
Set emp = New employee
For Each cell In row.Cells
'++++++++++++++++++++++++++++++++++++
'grab all values from payroll_journal
'populate VBA Bean - Employee Type
'++++++++++++++++++++++++++++++++++++
'*** header info *******************************************
emp.setJournalYear = Sheets("EFF_PAYROLL").Range("O3").value
emp.setJournalYearCell = "O3"
emp.setRegion = Sheets("EFF_PAYROLL").Range("P3").value
emp.setRegionCell = "P3"
emp.setDistrict = Sheets("EFF_PAYROLL").Range("Q3").value
emp.setDistrictCell = "Q3"
emp.setJournalNumber = Sheets("EFF_PAYROLL").Range("R3").value
emp.setJournalNumberCell = "R3"
'*** end header info *****************************************
'*** employee line item **************************************
emp.setName = cell.value
emp.setNameCell = cell.Address
emp.setClassCode = cell.Offset(0, 1)
emp.setClassCodeCell = cell.Offset(0, 1).Address
emp.setHourlyRate = cell.Offset(0, 2)
emp.setHourlyRateCell = cell.Offset(0, 2).Address
emp.setCertNumber = cell.Offset(0, 3)
emp.setCertNumberCell = cell.Offset(0, 3).Address
emp.setCommissary = cell.Offset(0, 46)
emp.setCommissaryCell = cell.Offset(0, 46).Address
emp.setTotalCommissary = cell.Offset(0, 46)
emp.setTotalCommissaryCell = cell.Offset(0, 46).Address
emp.setDay = cell.Offset(0, 51)
emp.setEDayCell = cell.Offset(0, 51).Address
emp.setMonth = cell.Offset(0, 52)
emp.setEMonthCell = cell.Offset(0, 52).Address
emp.setYear = cell.Offset(0, 53)
emp.setEYearCell = cell.Offset(0, 52).Address
emp.setchequeNo = cell.Offset(0, 54)
emp.setChequeNoCell = cell.Offset(0, 54).Address
emp.setAddress1 = cell.Offset(0, 57)
emp.setAAddress1Cell = cell.Offset(0, 57).Address
emp.setAddress2 = cell.Offset(1, 57)
emp.setAddress2cell = cell.Offset(1, 57).Address
'*** end employee line item *********************************
'*************footer info ***********************************
emp.setPreparedBy = Sheets("EFF_PAYROLL").Range("J39").value
emp.setPreparedByCell = Sheets("EFF_PAYROLL").Range("J39").Address
emp.setAuthorizedOfficer = Sheets("EFF_PAYROLL").Range("AE39").value
emp.setAuthorizedOfficerCell = Sheets("EFF_PAYROLL").Range("AE39").Address
emp.setPrintedName = Sheets("EFF_PAYROLL").Range("AD44").value
emp.setPritnedNameCell = Sheets("EFF_PAYROLL").Range("AD44").Address
'*************end footer info *******************************
employeeCollection.Add emp
' For Each emp In employeeCollection
' Debug.Print emp.getID & " " & emp.getName _
' ; vbCrLf & emp.getClassCode & " " _
' ; emp.getClassCodeCell
'
'
' Next emp
'
'
' Debug.Print employeeCollection.Count
'
'++++++++++++++++++++++++++++++++++++++
'END fetch of data from payroll_journal
'++++++++++++++++++++++++++++++++++++++
' If Not IsEmpty(cell.value) And errorFlag = False Then
'
'
'
' 'unprotect worksheets during writing process
' unProtectWS ("Cheque Template")
'
' ' unprotect workbook
' ActiveWorkbook.Unprotect ("***")
'
'
' Sheets("Cheque Template").Copy After:=Sheets(Sheets.Count)
' ActiveSheet.name = emp.name
'
'
'
'
' '******
' '** populate cheque with corresponding values - cell.Value
' '******
' 'Sheets(employee_name).Range("B7").Value = employee_name
' Sheets(emp.name).Range("B7").value = emp.name
'
'
' Sheets(emp.name).Range("D4").value = dayStr
' Sheets(emp.name).Range("C4").value = monthStr
' Sheets(emp.name).Range("B4").value = emp.year
' Sheets(emp.name).Range("H8").value = emp.certNumber
'
' Sheets(emp.name).Range("B8").value = emp.address1
' Sheets(emp.name).Range("B9").value = emp.address2
'
' 'journal number
' Sheets(emp.name).Range("H4").value = emp.year
' Sheets(emp.name).Range("I4").value = emp.region
' Sheets(emp.name).Range("J4").value = emp.district
' Sheets(emp.name).Range("K4").value = emp.journalNumber
' 'end journal number
'
' Sheets(emp.name).Range("B14").value = emp.regRate
' Sheets(emp.name).Range("F14").value = emp.regHours
'
' 'overtime hours and rate
' Sheets(emp.name).Range("B16").value = emp.overtimeRate
' Sheets(emp.name).Range("F16").value = emp.overtimeHours
' 'END overtime hours and rate
'
' Sheets(emp.name).Range("H14").value = emp.regTotal
' Sheets(emp.name).Range("H16").value = emp.overtimeTotal
' Sheets(emp.name).Range("B24").value = emp.commissary
' Sheets(emp.name).Range("H24").value = emp.totalCommissary
' Sheets(emp.name).Range("H18").value = emp.vacationTotal
' Sheets(emp.name).Range("H20").value = emp.totalPay
' Sheets(emp.name).Range("H29").value = emp.netPay
'
' 'cheque printout (bottom)
' Sheets(emp.name).Range("B47").value = emp.name
' Sheets(emp.name).Range("B48").value = emp.address1
' Sheets(emp.name).Range("B49").value = emp.address2
' Sheets(emp.name).Range("B43").value = Module3.SpellNumber(emp.netPay)
' Sheets(emp.name).Range("K45").value = Round(emp.netPay, 2)
'
' 'month and str on cheque portion
' Sheets(emp.name).Range("K40").value = emp.year & "/" & monthStr & "/" & dayStr
'
' 'printed name aka persons that approves cheque
' Sheets(emp.name).Range("J51").value = emp.printedName
'
'
'
'
'
'
' 'For Each emp In employeeCollection
' ' Perform validation on that employee
' ' Debug.Print emp.Name
' 'Next emp
'
'
'
'
'
'
'
'
'
'
' 'Module6.printWorksheet (emp.name)
' 'Module6.deleteWorksheet (emp.name)
'
'
'
' 'protect/lock cheque template before closing
'
' 'protectWS ("EFF_PAYROLL")
' protectWS ("Cheque Template")
'
' 'protect/lock workbook before closing
' ActiveWorkbook.Protect ("***")
'
' 'add employee to collection - used for later use
' 'employeeCollection.Add emp
'
'
' 'MsgBox "Cheque(s) will be printed."
'
'
' End If
Next cell
Next row
emp.validate
Exit Sub
End Sub
I notice in your code you have some lines commented out that previously appeared to have protected/unprotected the worksheet. If the sheet is still in a protected state, you will not be able to do this operation, and it will raise the 1004 error.
Solution
Unprotect the sheet (manually or via code) before formatting the cell.
OR, in the protection dialog, ensure that users are allowed to format cells:

VBA Class properties returning empty strings

I am trying to create a class in VBA for the first time. I have looked up some solutions and I don't see anything wrong with my class, but when I run the test code, the integer returns correctly but the strings return empty:
Class
Property Let Name(strName As String)
pName = strName
End Property
Property Get Name() As String
Name = pName
End Property
Property Let Class(strClass As String)
pClass = strClass
End Property
Property Get Class() As String
Class = pClass
End Property
Property Let Aggro(intAggro As Integer)
pAggro = intAggro
End Property
Property Get Aggro() As Integer
Aggro = pAggro
End Property
Test Procedure
Sub ClassTest()
Dim Dog1 As New Critter
Dog1.Name = "Labrador"
Dog1.Class = "Canine"
Dog1.Aggro = 0
Debug.Print Dog1.Name 'returns ""
Debug.Print Dog1.Class 'returns ""
Debug.Print Dog1.Aggro 'returns 0
End Sub
The only thing you have wrong is you haven't define private variables to hold your property values. It appears the integer is working because Integer initializes to 0, and you are 'setting' the value to 0. Just add this to the top of your class and try again:
Private pName as String
Private pClass as String
Private pAggro as Integer
:D

Accessing custom property's value gives 'Out of Memory' error when value is null

I'm trying to create a custom property in an excel sheet, then retrieve its value. This is fine when I don't use an empty string, i.e. "". When I use the empty string, I get this error:
Run-time error '7':
Out of memory
Here's the code I'm using:
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
The code fails at Debug.Print cprop.value. Shouldn't I be able to set the property to "" initially?
With vbNullChar it works, sample:
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
I think from the comments and the answer from Daniel Dusek it is clear that this cannot be done. The property should have at least 1 character to be valid, an empty string just isnt allowed and will give an error when the .Value is called.
So you Add this property with a length 1 or more string and you Delete the property again when no actual value is to be assigned to it.
As already mentioned it is not possible to set empty strings.
An easy workaround is to use a magic word or character, such as ~Empty (or whatever seems proof enough for you):
Dim MyProperty As Excel.CustomProperty = ...
Dim PropertyValue As String = If(MyProperty.Value = "~Empty", String.Empty, MyPropertyValue)
A slightly more expensive workaround but 100% safe is to start all the values of your custom properties with a character that you then always strip off. When accessing the value, systematically remove the first character:
Dim MyProperty As Excel.CustomProperty = ...
Dim PropertyValue As String = Strings.Mid(MyProperty.Value, 2)
You can write an extension to make your life easier:
<System.Runtime.CompilerServices.Extension>
Function ValueTrim(MyProperty as Excel.CustomProperty) As String
Return Strings.Mid(MyProperty.Value, 2)
End Function
Now you can use it like this: Dim MyValue As String = MyProperty.ValueTrim
Use a reversed principle when you add a custom property:
<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
To use like this: MyProperties.AddTrim(Name, Value)
Hope this helps other people who come across the issue..
Based on the other answers and some trial and error, I wrote a class to wrap a Worksheet.CustomProperty.
WorksheetProperty:Class
Sets and Gets the value of a Worksheet.CustomProperty and tests if a Worksheet has the 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
Usage
I have several properties of my custom Unit class return a WorksheetProperty. It makes it really easy to sync my database with my worksheets.
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
Simple Usage
'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