Cannot refer to an instance member of a class - vb.net

i would like to use the second property LogoWidth to set the width on the first property but im getting the "Cannot refer to an instance member of a class from a shared method"
If there's anyone that can help i'll appreciated
<DetailViewLayoutAttribute(LayoutColumnPosition.Left, "Header Logo", LayoutGroupType.SimpleEditorsGroup, 1)>
<VisibleInListView(False), DevExpress.Xpo.DisplayName("Logo"), ImmediatePostData> '<RuleRequiredField("Logo", DefaultContexts.Save)>
<ImageEditor(ListViewImageEditorMode:=ImageEditorMode.PictureEdit,
DetailViewImageEditorMode:=ImageEditorMode.PictureEdit, ListViewImageEditorCustomHeight:=85, DetailViewImageEditorFixedHeight:=160, DetailViewImageEditorFixedWidth:=160)>
<Size(SizeAttribute.Unlimited)>
Public Property Logo() As Byte()
Get
Return GetPropertyValue(Of Byte())("Logo")
End Get
Set
' If True Then
SetPropertyValue(Of Byte())("Logo", Value)
' End If
End Set
End Property
<DetailViewLayoutAttribute(LayoutColumnPosition.Right, "Header Logo", LayoutGroupType.SimpleEditorsGroup, 1)>
<VisibleInListView(False), DevExpress.Xpo.DisplayName("Width"), ImmediatePostData> '<RuleRequiredField("LogoWidth", DefaultContexts.Save)>
Public Property LogoWidth As Integer
Get
Return _LogoWidth
End Get
Set(ByVal Value As Integer)
SetPropertyValue(NameOf(LogoWidth), _LogoWidth, Value)
End Set
End Property}

This is not possible as instance members can be modified/called/are visible only by instances. The code below gives you a small piece of concept but here you can get more info about https://learn.microsoft.com/en-us/dotnet/visual-basic/language-reference/modifiers/shared
Class ClassTest
Public Property TestIsCalled As Integer
Public Sub IncreaseTestByInstance()
TestIsCalled += 1
End Sub
Shared Sub IncreaseTestByEveryWhereInNameSpace()
' Error
' Error - You MUST TO increase test by an instance method not by a shared method
' as TestIsCalled not exist when you call here as is an Instance Member not a Shared Member
TestIsCalled += 1
End Sub
End Class
So based on your code the solutions are two:
Change your Method (that you want to set LogoWidth inside it) in an
instance Sub or Function (what is it)
or change those two Properties in Shared Property.
All depends by your app scenarios.

Related

How to use instance of New Object in With... Block

Dim objects As New List(Of Object)
With New Object
.prop1 = "Property 1"
.prop2 = "Property 2"
objects.add(.instance) 'i mean instance of New Object
End With
is it possible.
I ask new question because last question has mislead information and I don't give right answer. so here code.
No it is not possible. The With statement basically creates an implicit variable. All you can do with that variable is access members and there is no member that returns a reference to the object itself.
If you want succinct code to create, populate and add an object to a list then do this:
myList.Add(New SomeType With {.SomeProperty = someValue,
.SomeOtherProperty = someOtherValue})
Interestingly, you can make it work the way you wanted if you create your own extension method. I was under the impression that you could not extend the Object class but either I was wrong or that has changed because I just tried in VB 2013 and it worked. You can write a method like this:
Imports System.Runtime.CompilerServices
Public Module ObjectExtensions
<Extension>
Public Function Self(Of T)(source As T) As T
Return source
End Function
End Module
and then do something like this:
With New SomeType
.SomeProperty = someValue
.SomeOtherProperty = someOtherValue
myList.Add(.Self())
End With
I'm not sure that that really provides any benefit though, given the availability of the object initialiser syntax that I demonstrated first.
Hmmm... I just realised that that's not actually extending the Object class. It was my original intention to try to do so but then I realised that a generic method was better because it would then return the same type as you call it on. I did just test it with a non-generic method extending type Object and it did still worked though.
You should to create your own class By example :
Public Class Car
Private _NumberCar As Integer
Public Property NumberCar() As Integer
Get
Return _NumberCar
End Get
Set(ByVal value As Integer)
_NumberCar = value
End Set
End Property
Private _ColorCar As Color
Public Property ColorCar() As Color
Get
Return _ColorCar
End Get
Set(ByVal value As Color)
_ColorCar = value
End Set
End Property
Private _OwnerName As String
Public Property OwnerName() As String
Get
Return _OwnerName
End Get
Set(ByVal value As String)
_OwnerName = value
End Set
End Property
End Class
and in the Class where you want to add the cars object do this :
Dim CarList As New List(Of Car)
Dim item As New Car
With item
.NumberCar = 1243
.ColorCar = Color.Red
.OwnerName = "Ibra"
End With
CarList.Add(item)
strong text

Accessing Items in a Collection from a Class

-EDIT Fixed
I was missing one thing and doing one thing wrong. First I was missing a function to access the collection by index. And I should of been using a for Loop instead of a for each loop in my module code
I forgot to add this to the collection class
Public Function GetPayRecords(ByVal index As Variant) As PayRecords
Set GetPayRecords = pObjCol.item(index)
End Function
and replaced
For Each vItem In .GetPayRecords
....code to do stuff
Next vItem
with this in the module
Dim x As Integer
For x = 1 To .Count
Debug.Print .GetPayRecords(x).PY_PayRecord.CEOCompanyID
Debug.Print .GetPayRecords(x).PY_PayRecord.OrigBankID
Next x
I'm writing a program that has 8 Classes. Each class represents a specific record type.
I have an overall Class that contains those 8 classes which is for simplicity when coding in the Module. I only have to declare one class which gives me access to all 8 classes. I have a collection which contains all the records types. Once all the logic of loading the individual records is complete they get added to the collection. This all works perfectly and I can see all the records in the collection. The final step, which happens to be where i'm having the problem, I need to extract each item within the collection by record type and write it to a csv. The problem I encounter is trying to iterate through each record.
Here's how the structure looks
Classes
clsAllRecordTypes
clsRecordType1
clsRecordType2
...
clsRecordType8
Collection
clsColRecords
The problem is in the retrieval
Module
Dim PayRecord As PayRecords 'Class of Classes
Dim PayRecordList As bankCollection
...code to load all the payrecords
With payrecordlist
Foreach vItem in .pObjCol
debug.print .pObjCol.Item(?) ' not sure why i can't see all 8
next vItem
End With
When I add vItem to the watch I can see each and every record type filled up with information but yet i Can not access it. Below is the Class of classes and collection
Class of Classes
Option Explicit
'This class is a representation of all the record types that apply to our Payment Manager
'It aggregates all the record types (classes) into one class. That one class is used in the main processing module for simplicty
'
Private pPayRecord As New PayRecord
Private pPNAR_OP As New PNAR_OP
Private pPNAR_RP As New PNAR_RP
Private pSuppACHREC As New SuppACHRec
Private pSuppCCRRec As New SuppCCRRec
Private pSuppCHKRec As New SuppCHKRec
Private pDocumentDelieveryRec As New DocumentDeliveryRecord
Private pInvoiceRecords As New InvoiceRecords
Public Property Get PY_PayRecord() As PayRecord
Set PY_PayRecord = pPayRecord
End Property
Public Property Let PY_PayRecord(ByVal newPayRecord As PayRecord)
Set pPayRecord = newPayRecord
End Property
Public Property Get PA_PNAR_OP() As PNAR_OP
Set PA_PNAR_OP = pPNAR_OP
End Property
Public Property Let PA_PNAR_OP(ByVal newPNAR_OP_Record As PNAR_OP)
Set pPNAR_OP = newPNAR_OP_Record
End Property
Public Property Get PA_PNAR_RP() As PNAR_RP
Set PA_PNAR_RP = pPNAR_RP
End Property
Public Property Let PA_PNAR_RP(ByVal newPNAR_RP_Record As PNAR_RP)
Set pPNAR_RP = newPNAR_RP_Record
End Property
Public Property Get AC_SuppACH() As SuppACHRec
Set AC_SuppACH = pSuppACHREC
End Property
Public Property Let AC_SuppACH(ByVal newSuppACH_Record As SuppACHRec)
Set pSuppACHREC = newSuppACH_Record
End Property
Public Property Get AC_SuppCCR() As SuppCCRRec
Set AC_SuppCCR = pSuppCCRRec
End Property
Public Property Let AC_SuppCCR(ByVal newSuppCCR_Record As SuppCCRRec)
Set pSuppCCRRec = newSuppCCR_Record
End Property
Public Property Get AC_SuppCHK() As SuppCHKRec
Set AC_SuppCHK = pSuppCHKRec
End Property
Public Property Let AC_SuppCHK(ByVal newSuppCHK_Record As SuppCHKRec)
Set pSuppCHKRec = newSuppCHK_Record
End Property
Public Property Get DocumentDeliveryRecord() As DocumentDeliveryRecord
Set DocumentDeliveryRecord = pDocumentDelieveryRec
End Property
Public Property Let DocumentDeliveryRecord(ByVal newDocumentDeliveryRecord As DocumentDeliveryRecord)
Set pDocumentDelieveryRec = newDocumentDeliveryRecord
End Property
Public Property Get InvoiceRecords() As InvoiceRecords
Set InvoiceRecords = pInvoiceRecords
End Property
Public Property Let InvoiceRecords(ByVal newInvoiceRecord As InvoiceRecords)
Set pInvoiceRecords = newInvoiceRecord
End Property
Collection Class
Option Explicit
Private pHeaderRec As New HeaderRec
Private pNewPayRecords As New PayRecords
Public pObjCol As Collection
Private pTrailerRec As New TrailerRec
Private Sub Class_Initialize()
Set pObjCol = New Collection
End Sub
Private Sub Class_Terminate()
Set pObjCol = Nothing
End Sub
Public Property Get HD_HeaderRecord() As HeaderRec
Set HD_HeaderRecord = pHeaderRec
End Property
Public Property Let HD_HeaderRecord(ByVal newHeaderRecord As HeaderRec)
Set pHeaderRec = newHeaderRecord
End Property
Sub Add(ByVal newPayRecs As PayRecords)
pObjCol.Add newPayRecs
End Sub
Property Get Count() As Long
Count = pObjCol.Count
End Property
Public Property Get TR_TrailerRecord() As TrailerRec
Set TR_TrailerRecord = pTrailerRec
End Property
Public Property Let TR_TrailerRecord(ByVal newTrailer_Record As TrailerRec)
Set pTrailerRec = newTrailer_Record
End Property
I'm sorry if this doesn't help, because your explanation is hard to follow. But, I'll assume that you are saying that you have an object of type Payrecords, which contains references to seven other objects of types PNAR_OP, PNAR_RP, etc. Each of these latter objects contain "20-30 fields" that you want to get at. You ask how to loop through all of these.
A simple way to do that is to use an array. Yes, you can foreach through Collections or (better yet) Dictionaries, but arrays work, they're easy to understand, and they were iterating through objects when Collections were running around in diapers.
Let your Payrecords have a property of type Object(6). When you initialize it, instantiate one of each of the seven objects and add it to the array (for example, "Set myPayrecordsObjects(3) = New SubCCRRec" and so on). To loop through, just use a for next loop to loop through the 7 objects.
Since you provide no information about how you structure your "fields" within these objects, I'll recommend that you iterate through the Fields collection of the ADO object to loop through those. (If you're not using the ADO Fields collection, well, your attention to detail gets mine in return.)

Access variable of child form

Using VB.Net
I have about 60 Child forms
Each have a variable with same name.
In Main form I want to set the value of the variable of the active child.
One way of doing that is like
Select Case Me.ActiveMdiChild.Name
Case "formName"
frmformName.Variable=0
I donot want to do that as it involves writing many cases and I may miss some.
Is there some other way of doing it .
I tried
Dim O as Object = Me.ActiveMdiChil
O.VariableName= 0
and its various variants but its not working
Another way to do that is with an Interface, example:
Public Interface IChildVariable
Property Variable() As Integer
End Interface
Public Class Form1
Implements IChildVariable
Private _MyVariable As Integer
Public Property Variable() As Integer Implements IChildVariable.Variable
Get
Return _MyVariable
End Get
Set(ByVal value As Integer)
_MyVariable = value
End Set
End Property
End Class
Then you can just have a single check point:
If TypeOf Me.ActiveMdiChild Is IChildVariable Then
DirectCast(Me.ActiveMdiChild, IChildVariable).Variable = 0
Else
''Throw Exception
End If

VB.NET - Access shared member through Type

I'm wondering if this is possible. In my Test function below I want to
Check if T is of type BaseClass; throw an error if it's not.
Get the value of SomeText property of BaseClass.
Class BaseClass
Public Shared Property SomeText As String
End Class
Class Class1
Inherits BaseClass
Public Sub New()
SomeText = "Class 1 here"
End Sub
End Class
...
Sub Main
Test(GetType(Class1))
Test(GetType(Class2))
End Sub
Sub Test(T As Type)
' Task 1: Check if T is of type BaseClass
' Task 2: Get the value of SomeText property of BaseClass
End Sub
You can keep your test signature and do the following:
If T.BaseType Is GetType(BaseClass) Then
Dim CurrentValue as String = BaseClass.SomeText
Else
Throw New ArgumentException("T must inherit from BaseClass")
End If
Since this never actually creates an instance of your type, you may not get the string you are expecting. If you haven't created an instance elsewhere you will only have an empty string.
You can generate an instance of your class from the type you sent if that is your goal:
If T.BaseType Is GetType(BaseClass) Then
Dim currentValue As String = CType(Activator.CreateInstance(T), BaseClass).SomeText
Else
Throw New ArgumentException("T must inherit from BaseClass")
End If
Edit based on Comment about further subclassing:
If you want it to include the base type or any descendants you could use this if instead:
If T Is GetType(EventBase) OrElse T.IsSubclassOf(GetType(EventBase)) Then
End If
Rewrite test as follows (updated to reflect change to question):
Sub Test(T As Type)
' Task 1: Check if T is of type BaseClass
If T.IsSubclassOf(GetType(BaseClass)) Then
' Task 2: Get the value of SomeText property of BaseClass
Dim sValue As String
' Create an unused instance of BaseClass to ensure the current value of SomeText is assigned
Dim oClass As BaseClass = DirectCast(System.Activator.CreateInstance(T), BaseClass)
' Get the value from BaseClass since it is a shared instance
sValue = BaseClass.SomeText
Else
Throw New ArgumentException("T did not inherit from BaseClass")
End If
End Sub

Is this some kind of referencing problem? Value not sticking

Apologies for the appalling title.
I have mocked up this code to mimic an issue I was encountering on a project.
I want to know why the property status does not 'stick'. Stepping through the code I can even see it setting the property!
Is it something to do with Structure being a value type?
Here is the code, it is standalone.
Imports System.Diagnostics
Public Class clsTest
Public Shared Sub test()
Dim myHolder As New holder
myHolder.info = New info(5)
With myHolder.info
Debug.Print("Initialised Status : {0}", .status)
Debug.Print("Initialised Original Status : {0}", .originalStatus)
myHolder.setStatusToTen()
Debug.Print("Next Status : {0}", .status)
Debug.Print("Next Original Status : {0}", .originalStatus)
End With
End Sub
End Class
Public Class holder
Private _heldInfo As info
Public Property info() As info
Get
Return _heldInfo
End Get
Set(ByVal value As info)
_heldInfo = value
End Set
End Property
Public Sub setStatusToTen()
_heldInfo.status = 10
End Sub
End Class
Public Structure info
Private _iOriginalStatus, _iStatus As Integer
Public Sub New(ByVal iStartingStatus As Integer)
_iOriginalStatus = iStartingStatus
End Sub
Public ReadOnly Property originalStatus() As Integer
Get
Return _iOriginalStatus
End Get
End Property
Public Property status() As Integer
Get
Return _iStatus
End Get
Set(ByVal value As Integer)
_iStatus = value
End Set
End Property
End Structure
When I run clsTest.test I get the following output-
clsTest.test
Initialised Status : 0
Initialised Original Status : 5
Next Status : 0
Next Original Status : 5
...even though setStatusToTen is doing exactly what it says on the tin!
This is yet another case of mutable structs being evil. Avoid using structures for this purpose. As a reference:
Why are mutable structs “evil”?
Yes, its because Structures are value types. When a struct object is assigned to another struct object, the full content of the struct is copied and duplicated. (See this C# example)
So in your code, this set:
Set(ByVal value As info)
_heldInfo = value
End Set
... effectively results in two copies of the structure being made. One is internal to holder and is represented by _heldInfo, and the other is 'external' to holder, and is represented by myHolder.info. After the copy has been made, when you set values on one of them, the other is not affected.
If you add this method to holder:
Public Sub printStatus()
Debug.Print("Internal Status : {0}", _heldInfo.status)
End Sub
... you will find where your value of 10 went.