Modify the components of the main class through another class - vb.net

We have a school project and I'm trying to break our code into groups. I set my FormBorderStyle to None so I can modify it. But can I use another class to modify the components I have in my main?
An example would be:
Public Class main
Private Sub btn_title_bar_exit_Click(sender As Object, e As EventArgs) Handles btn_title_bar_exit.Click
Me.Close()
End Sub
Private Sub btn_title_bar_minimize_Click(sender As Object, e As EventArgs) Handles btn_title_bar_minimize.Click
Me.WindowState = FormWindowState.Minimized
End Sub
End Class
Public Class user_interface
'Modify components and the form through here
'example: btn_exit.ForeColor = Color.Black
'example: Me.Close()
End Class
Also wondering, this a good way to break code?

If you just want to separate routines (functions/methods/variables declarations...) because you have loads of code filling your class file, just use :
1) the Partial keyword
Public Partial Class MainClass
' MAIN CONTENT
Public Sub New()
Me.InitializeComponents()
' ...
End Sub
' ...
End Class
and in another file :
Public Partial Class MainClass
' USER INTERFACE HANDLERS...
'Modify components and the form through here
'example: btn_exit.ForeColor = Color.Black
'example: Me.Close()
' ...
End Class
So this is the same Class, and other classes may NOT be able to access/modify its members.
2) or either use #Region to split your code and group them :
Public Class MainClass
#Region "Instanciation..."
Public Sub New()
Me.InitializeComponents()
' ...
End Sub
#End Region
#Region "User Interface..."
'Modify components and the form through here
'example: btn_exit.ForeColor = Color.Black
'example: Me.Close()
Public Sub btn1_Click(...)
Public Sub Picture1_MouseMove(...)
#End Region
#Region "Public Properties..."
'...
#End Region
End Class
Then use the plus/minus to unfold/fold that part of the code.
If you really want to edit the members of your MainClass from another class, say, RemoteClass, there are TONs of way doing it, and it depends on what exactly you want to do.
You could make everything Public in your MainClass :
Locate your Form designer file (the one containing the declaration of all the controls of your Form) and change each declaration to Public.
Private pictureBox1 As Picturebox
' becomes
Public pictureBox1 As Picturebox
(Or just click on a control in the IDE, and change its accessibility level to Public)
Then if you can pass a variable pointing to an instance of MainClass in an instance of RemoteClass, then, through RemoteClass, you can access TheMainClassInstance.pictureBox1, and change its size, location, etc. everything.
Then how to create an instance of MainClass in RemoteClass ? It depends on the structure of your application... Without details, guess what.. we'll have to guess..!
Public Class RemoteClass
Private _InstanceOfMainClass As MainClass = Nothing
Public Sub New(ByRef NewInstanceOfMainClass As MainClass)
_InstanceOfMainClass = NewInstanceOfMainClass
' ^^ this is one way doing it.
' ...
End Sub
' ...
Private Sub ChangeBackgroundColor()
_InstanceOfMainClass.picturebox1.BackColor = Color.Black ' and voila !
End Sub
End Class
Then you have a MainClass in your RemoteClass. Don't forget to dispose of _InstanceOfMainClass to avoid Memory Leak (I assume you know how to..)
How many instances of MainClass do you have ?
If it's just one, and you have several RemoteClass classes, then you could consider to make the member of MainClass you want to access as static (shared) members.
Public Class MainClass
Private Shared _MyInstance As MainClass = Nothing
Private Shared Sub InitializeMyInstance()
If _MyInstance Is Nothing Then
_MyInstance = New MainClass(...)
Else
If _MyInstance.IsDisposed Then
' Requires an IDisposable interface
' and handling of Me.Closed event elsewhere...
_MyInstance = Nothing
_MyInstance = New MainClass(...)
End If
End If
End Sub
Public Shared ReadOnly Property MyInstance() As MainClass
Get
InitializeMyInstance()
Return _MyInstance
End Get
End Property
Public Shared ReadOnly Property PictureBox1() As PictureBox
Get
Return MyInstance.pictureBox1
End Get
End Property
' Create as many Properties as required...
End Class
Then in ANY RemoteClass instance, you just call :
MainClass.PictureBox1.Width = 400
MainClass.Close()
MainClass.PictureBox1.Height = 200
But as I said, this works only if you only have a single instance of MainClass.
If you have several MainClass instances and several RemoteClass instances, consider using Unique IDs and a static function/property to access a specific instance.
How to create an ID ?
Public Class MainClass
Private Shared _NextID As Integer = 0
Private _ID As Integer
Public ReadOnly Property ID() As Integer
Get
Return _ID
End Get
End Property
Public Sub New(...)
Me.InitializeComponents()
' ...
_ID = _NextID
_NextID = _NextID + 1
End Sub
' ...
End Class
Then... Create a sorted list containing all the IDs :
Public Class MainClass
Private Shared _IDsList As New SortedList(Of Integer, MainClass)
' then edit your New() method :
Public Sub New(...)
Me.InitializeComponents()
' ...
_ID = _NextID
_NextID = _NextID + 1
_IDList.Add(_ID, Me)
End Sub
' ...
End Class
Then create a static function to get a specific instance of MainClass by its ID.
Public Class MainClass
' ...
Public Shared Function GetInstanceByID(ByVal iID As Integer) As MainClass
If _IDList.ContainsKey(iID) Then
Return _IDList.Item(iID)
Else
Return Nothing
End If
End Function
' ...
' And create the appropriate Dispose() method
' the appropriate Clear() method
' the appropriate FormClosing events handlers
' etc. etc. etc.
End Sub
the thing is, we don't know what's the purpose of your MainClass, and why RemoteClass instances have to modify MainClass members (which members by the way ? controls, variables, add/remove controls ?)

Related

Access a base class property in inheritance class

I'm using the base class Button in VB.net (VS2017) to create a new class called CDeviceButton. The CDeviceButton then forms as a base for other classes such as CMotorButton, CValveButton.
I want to set the Tag property in the child class CMotorButton but access it in the constructor in CDeviceButton. Doesn't work for me. It turns up being empty.
The Tag is set in the standard property when inserting the CMotorButtom instance into a form.
I've also tried to ensure teh the parent classes' constructors are run by setting mybase.New() as the first action in each constructor but that didn't change anything.
Any ideas for improvements?
Public Class CDeviceButton
Inherits Button
Public MMIControl As String = "MMIC"
Public Sub New()
MMIControl = "MMIC" & Tag
End Sub
End class
Public Class CMotorButton
Inherits CDeviceButton
Sub New()
'Do Something
end Sub
End Class
When you try to concatenate Tag with a string, you are trying to add an object that is probably nothing. I set the Tag property first and used .ToString and it seems to work.
Public Class MyButton
Inherits Button
Public Property MyCustomTag As String
Public Sub New()
'Using an existing Property of Button
Tag = "My Message"
'Using a property you have added to the class
MyCustomTag = "Message from MyCustomTag property : " & Tag.ToString
End Sub
End Class
Public Class MyInheritedButton
Inherits MyButton
Public Sub New()
If CStr(Tag) = "My Message" Then
Debug.Print("Accessed Tag property from MyInheritedButton")
Debug.Print(MyCustomTag)
End If
End Sub
End Class
And then in the Form
Private Sub Test()
Dim aButton As New MyInheritedButton
MessageBox.Show(aButton.Tag.ToString)
MessageBox.Show(aButton.MyCustomTag)
End Sub
Below is my solution I came up with that works. Basically I make sure that all initialization has taken place before reading the Tag property. What I experienced is that the Tag property is empty until the New() in CMotorButton has completed, even though the Tag property has been set when creating the instance of CMotorButton in the Form. TimerInitate has a Tick Time of 500 ms.
Not the most professional solution but works for what I need at the moment.
Another option could be multi threading but that I haven't tried and leave that for future tryouts.
Public Class CDeviceButton
Inherits Button
Public MMIControl As String = "MMIC"
Public Sub New()
TimerInitiate = New Timer(Me)
End Sub
Private Sub TimerInitiate_Tick(sender As Object, e As EventArgs) Handles TimerInitiate.Tick
If Tag <> Nothing Then
TimerInitiate.Stop()
MMIControl = "MMIC" & Tag
End If
End Sub
End class
Public Class CMotorButton
Inherits CDeviceButton
Sub New()
'Do Some stuff
TimerInitiate.Start()
End Sub
Private Sub CMotorButton_Click(sender As Object, e As EventArgs) Handles Me.Click
End Class

Best way to expose an object with read-only properties only

I can't find an answer to my question so I'm asking a new one.
I have an object where I want to fill it's properties from another class in the same solution. But the object should expose read-only properties only so the outside-caller can't see nor access the setter (cause there is no setter).
What is the best way to fill the internal backing variables from the same solution? I know I could do it in the constructor but I want to be able to set the variables after creating the object.
Sorry for my weird explaination, maybe a bit of code could help.
This is what I'm doing now:
Public Class ReadonlyObject
Protected Friend Sub New()
End Sub
'Could use this, but don't want to...
Protected Friend Sub New(foo As String)
End Sub
Friend _foo As String
Public ReadOnly Property Foo As String
Get
Return _foo
End Get
End Property
End Class
Public Class FillReadonlyObject
Private Sub DoSomeHeavyWork()
Dim roObject As New ReadonlyObject
roObject._foo = "bar"
'Could use this, but don't want to...want to access properties directly.
Dim roObject2 As New ReadonlyObject("bar")
End Sub
End Class
With this, the ReadonlyObject's properties are correctly exposed as readonly but I'm afraid it's bad practice.
I've seen implementations like this:
Public Class ReadonlyObject
Protected Friend Sub New()
End Sub
Private _foo As String
Public Property Foo As String
Get
Return _foo
End Get
Friend Set(value As String)
_foo = value
End Set
End Property
End Class
Public Class FillReadonlyObject
Private Sub DoSomeHeavyWork()
Dim roObject As New ReadonlyObject
roObject.Foo = "bar"
End Sub
End Class
This works, but exposes the property with a setter. It's not accessible, but it's visible and I don't want that :)
So maybe it's only a cosmetic thing but I think it's nice to tell the caller (or at least intellisense) the property is strictly read-only.
Thanks, Jan
If you want to explicitly declare the property as read-only, but then still have a way to set it after it is constructed, then all you need to do is create your own setter method rather than using the one automatically created for you but the property. For instance:
Public Class ReadonlyObject
Protected Friend Sub New()
End Sub
Private _foo As String
Public ReadOnly Property Foo As String
Get
Return _foo
End Get
End Property
Friend Sub SetFoo(value As String)
_foo = value
End Sub
End Class
Public Class FillReadonlyObject
Private Sub DoSomeHeavyWork()
Dim roObject As New ReadonlyObject
roObject.SetFoo("bar")
End Sub
End Class
Or, you could create two properties, like this:
Public Class ReadonlyObject
Protected Friend Sub New()
End Sub
Public ReadOnly Property Foo As String
Get
Return HiddenFoo
End Get
End Property
Friend Property HiddenFoo As String
End Class
Public Class FillReadonlyObject
Private Sub DoSomeHeavyWork()
Dim roObject As New ReadonlyObject
roObject.HiddenFoo = "bar"
End Sub
End Class

Hiding function on nested class

Public Class Class1
Private names As List(Of String)
Private _class2 As New Class2
Public Sub AddName(ByVal name As String)
names.Add(name)
_class2.Add()
End Sub
Public ReadOnly Property AddAge(ByVal name As String) As Class2
Get
_class2.index = names.IndexOf(name)
Return _class2
End Get
End Property
Public Sub Clear()
names.Clear()
_class2.Clear()
End Sub
Public Class Class2
Private _age As List(Of Integer)
Protected Friend index As Integer
Public Property Age() As Integer
Get
Return _age(index)
End Get
Set(ByVal value As Integer)
_age(index) = value
End Set
End Property
Public Sub Add()
_age.Add(0)
End Sub
Public Sub Clear()
_age.Clear()
End Sub
End Class
End Class
How can I hide ,Sub Clear and Sub Add on class2, so they'll only be visible on class1, like;
Public Sub Clear()
names.Clear()
_class2.Clear() '<<<<<<<
End Sub
I want they do not be visible on Sub Main(), like they are below.
Sub Main()
Dim person As New Class1
person.AddAge("kid").Clear() '<<<<<<
person.AddAge("kid").Add() '<<<<<<
End Sub
If I put Protected, I class1 cannot access it. If I put Protected Friend, Sub Main() can still access them. Thanks for your help and time.
Used -Hans Passant- comment.
"Trust in .NET follows assembly boundaries. If you get two classes in one assembly then there are two programmers that know how to find each other if there's a problem. The only way to get what you want is to put these classes in a separate class library project. Which then lets you use Friend. And whomever writes that Main method doesn't have to be friendly."

Organizing VB.Net Mehods

Say I have a class with several methods within it. I want to organize the methods into groupings that can be accessed without constructing a new object each time. The purpose is to group the methods of the class into logical buckets
For instance:
Dim myclass as MyCustomClass
myclass.Shipping.Get_List()
myclass.Production.Get_List()
What is the best way to do this? I tried nested classes, but VB.NET won't let me access the methods as shown above.
so this is how i would do what you want
this is not the best design of the world but it would work
I would suggest you to move the actual get_list and other kind of method / property into the specific class while keeping the common one in the parent class, which in this case is test
but then, I have no idea what your code look like so from that point on, it's your choice
Module Module1
Sub Main()
Dim test As New test
test.Production.Get_List()
test.Shipping.Get_List()
End Sub
End Module
Public Class Shipping
Private parent As test
Public Sub New(ByRef parent As test)
Me.parent = parent
End Sub
Public Function Get_List() As List(Of Integer)
Return parent.GetShipping_List
End Function
End Class
Public Class Production
Private parent As test
Public Sub New(ByRef parent As test)
Me.parent = parent
End Sub
Public Function Get_List() As List(Of Integer)
Return parent.GetProduction_List
End Function
End Class
Public Class test
Public Property Production As Production
Public Property Shipping As Shipping
Public Function GetShipping_List() As List(Of Integer)
Return Nothing
End Function
Public Function GetProduction_List() As List(Of Integer)
Return Nothing
End Function
Public Sub New()
Production = New Production(Me)
Shipping = New Shipping(Me)
End Sub
End Class
With caution that you more than likely should re-evaluate your architecture, you could implement your pattern like this:
Public Class MyCustomClass
Private _shippingList As List(Of String)
Private _productionList As List(Of String)
Public Production As ProductionClass
Public Shipping As ShippingClass
Public Sub New()
Production = New ProductionClass(Me)
Shipping = New ShippingClass(Me)
End Sub
Public Class ShippingClass
Private _owner As MyCustomClass
Public Sub New(owner As MyCustomClass)
_owner = owner
End Sub
Public Function Get_List()
Return _owner._productionList
End Function
End Class
Public Class ProductionClass
Private _owner As MyCustomClass
Public Sub New(owner As MyCustomClass)
_owner = owner
End Sub
Public Function Get_List()
Return _owner._productionList
End Function
End Class
End Class
However, if your true intent is simply organizing the methods in a more accessible and logical manner, I would suggest considering:
Public Class MyCustomClass
Public Sub ShippingListGet()
End Sub
Public Sub ShippingListAddTo()
End Sub
Public Sub ShippingThatDO()
End Sub
Public Sub ShippingThisDo()
End Sub
Public Sub ProductionListGet()
End Sub
Public Sub ProductionListAddTo()
End Sub
Public Sub ProductionThisDo()
End Sub
Public Sub ProductionThatDo()
End Sub
End Class
Keep in mind, some people consider that difficult to read. I personally prefer organization along those lines so when the methods are sorted alphabetically they group logically.
I have found the solution I was looking for using interfaces
Public Interface ICompany
Function Company_List() As DataTable
End Interface
Public Class MainClass
Public Company As ICompany = New CompanyClass
Public Sub New()
MyBase.New()
End Sub
Private Class CompanyClass
Public Sub New()
MyBase.New()
End Sub
Public Function Company_List() As DataTable
My code....
End Function
End Class
End Class

how to access class from inherited class

I have two classes:
class class2
inherits class1
public sub modify()
'modify property of class1
end sub
end class
How can I modify class1 in a sub in class2?
You just call it. Example:
Public Class class1
Private _Value As String = String.Empty
Property Value() As String
Get
Return _Value
End Get
Set(ByVal value As String)
_Value = value
End Set
End Property
End Class
Public Class class2
Inherits class1
Public Sub modify()
Value = "modified"
End Sub
End Class
And to show it works:
Dim c2 As New class2
c2.modify()
MessageBox.Show(c2.Value)
You are asking about properties, note that only protected and public properties are visible to inherited classes.
You need the MyBase keyword when you are overriding an existing function in the parent class. Other protected or public properties or functions can be accessed regulary without any special keyword.
One tip I wanted to add to the above comments regarding accessing base class info is where you have a base class without a default contructor or want to use a specific constructor This is a good opportunity to use Mybase. You have to call the constructor before any additional actions take place in this scenario.
Public Class MyClass
Inherits baseClass
Public Sub New()
mybase.new("Oranges")
End Sub
End Class
Public Class baseClass
Private _someVariable as String
Public Sub New(byval passedString as string)
_someVariable = passedString
End Sub
End Class