How to access a new instantiated class method from another function in another class? - vb.net

I feel comfortable when instantiating a class, then using it within the same function, but now I need to instantiate a class from a toolbar button:
Dim pll As New Polyline()
Debug.WriteLine("TSB_Polyline_Click:: a new polyLine is born : " & pll.Count)
pll.AddPoint(0, 0)
And then I need to run the pll.AddPoint from my class method in another sub:
Public Sub MyEvent(sender as object, e as myEvent) Handles myEvent
Dim x as Double, y as Double
pll.AddPoint(x,y)
There I have my error (System.NullReferenceException: 'Object reference not set to an instance of an object.'), pll = Nothing (no error in my constructor, my class worked from the toolbar button_Click)
I tried to declare pll public and shared:
Public Shared pll As Polyline
And even to import it:
Imports oGIS.Polyline
Nothing works. My Class is instanciated in the first Sub (toolbar button), but somehow dies when leaving the Sub...
Is there any other solution that doing it using VB6 instead of VB.Net ?
I am a bit desesperate, I found no such topic anywhere on Google...

If you need to access a variable in more than one method then it should be declared outside all of them. It should be Private if you don't need to access it outside the type it's declared in and it should only be Shared if you specifically need all instances of the class accessing the same object. In your case, Private and not Shared is the obvious choice:
Private pll As Polyline
You now set that field in the first method and get it in the second.

I am guessing a partial look at your class would be something like this...
Public Class Polyline
Public ReadOnly Property CountOfPoints As Integer
Get
Return ListOfPoints.Count
End Get
End Property
Public Property ListOfPoints As New List(Of Point)
Public Sub AddPoint(x As Integer, y As Integer)
Dim p As New Point(x, y)
ListOfPoints.Add(p)
End Sub
End Class
Declare a class level (in this case the class is a Form) variable which can be seen and used by any method in your form.
Public Class Form1
Private LocalPolyLine As Polyline
'This is a local list, not part of the class
'It is a list of the number of instances of the class you have created
Private ListOfLines As New List(Of Polyline)
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
'Pretend this is a button on your toolbar used to create a new line
'Each time you click this button you have a completely new line with no points
LocalPolyLine = New Polyline
'If you want to keep track of how many lines you have...
ListOfLines.Add(LocalPolyLine)
End Sub
Private Sub AddPoint(x As Integer, y As Integer)
Debug.Print($"Number of Lines is {ListOfLines.Count}")
Debug.Print($"Number of points on current line {LocalPolyLine.CountOfPoints}")
LocalPolyLine.AddPoint(x, y)
Debug.Print($"Number of points on current line {LocalPolyLine.CountOfPoints}")
End Sub
'To see all the points on the line...
Private Sub ViewPoints()
For Each p In LocalPolyLine.ListOfPoints
Debug.Print($"The coordinates of the point are {p.X},{p.Y}")
Next
End Sub
End Class

Related

Listbox breaks when setting it to a virtual instance from a class

I have a weird problem that I can't wrap my head around.
I have the following code:
Public Class Form1
Public WithEvents MyClass1 As New MyClass
Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
End Sub
Private Sub MyClass_UpdateListbox() Handles MyClass1.UpdateListbox
For Each sItem as String In MyClass1.Listbox
MsgBox(sItem) 'an MsgBox shows correct items each time.
Next sItem
Me.Listbox = Me.MyClass1.Listbox 'doesn't work and breaks listbox.
Me.Listbox.Items.Clear() 'listbox is empty anyway, but has no effect.
Me.Listbox.Items.Add("event triggered") 'does nothing.
End Sub
End Class
Public Class MyClass
Public Listbox as new Listbox
Public Event UpdateListbox()
Public Sub New()
'Constructor. sub.
Me.AddItem("Populating listbox")
End Sub
Public Sub AddItem(sItem as String)
Me.Listbox.Items.Add(sItem)
RaiseEvent UpdateListbox()
End Sub
End Class
If I comment the following lines in above code, the listbox keeps adding event triggered, as expected. Of course, I don't have to remove the clear one. It will work, but then it just adds the same item. If I use a command button and call MyClass.AddItem("Something") that is correctly added too as long as the below is commented out. But if not, then once the listbox is in broken state, nothing can be added anymore.
Me.Listbox = Me.MyClass1.Listbox 'doesn't work and breaks listbox.
Me.Listbox.Items.Clear() 'listbox is empty anyway, but has no effect.
How can I use a virtual listbox and assign it to my real listbox?
Also, instead of assigning one listbox to the other, I can of course use that for each loop and add each item one by one which works, but that for each look was for debugging purpose in the first place.
EDIT:
My goal with this application is to build a Todo list with features that are not in a todolist. This is a project I build for work because there I need a tool like this. I already have a todolist that I use but I built it wrong in the past. Everything was condensed in form1, no modules no extra classes. As a result I got weird bugs that I patched with workarounds. I am now rebuilding the application from the ground up, separating tasks in its own classes so I can apply business logic and have a true OOP application. The todo list will become its own class, and managing the list etc will be handeled by this class. It interacts with controls on the form, such as buttons and listboxes. If I just use form1.listbox from the class, things break at program start. I started another question and the below code was a now deleted answer. At first I did not get it working because I did not realize the listbox crashes if I assign it the virtual instance.
So my goal is to have the todolist be handled entirely by the todolist class. It does need a way to interact with controls on form1, and that is the puzzle I'm currently trying to solve.
In the original code, the main problem is that the Field that hold the instance of a Control shown if a Form is reassigned to the instance of another ListBox Control defined in a custom class:
Me.Listbox = Me.MyClass1.Listbox
From now on, Me.Listbox points another ListBox that is not show on screen, so any attempt to update the Form's child ListBox fails, except when Me.Listbox.Items.Clear() is called - in the same procedure - after it's being reassigned, because the handle of the Owner of the ObjectCollection (the object that holds the Items shown in the ListBox) has not been updated yet. It's going to fail after the current method exits nonetheless.
As noted in comments, this is a simplified method to handle a Form and its child Controls using a handler class. The contract between the class handler and a Form is sealed by an Interface (named IFormHandler here).
A Form that implements this Interface exposes the methods defined by the Interface that allow to trigger Actions and specific behaviors, depending on the Type of Control and the implementation.
I suggest to take a look at the MVP or ReactiveUI (MVVM-derived) for WinForms Patterns.
How too proceed:
Open up the ApplicationEvents class object.
If you don't have it already, select Project -> Properties -> Application and click the View Application Events button. It will generate ApplicationEvents.vb. Find it in Solution Explorer and open it up.
It should look like this (plus a bunch of comments that explain what it's for):
Imports Microsoft.VisualBasic.ApplicationServices
Namespace My
Partial Friend Class MyApplication
End Class
End Namespace
Paste into MyApplication these lines of code:
Imports Microsoft.VisualBasic.ApplicationServices
Namespace My
Partial Friend Class MyApplication
Public SomeFormHandler As MyFormHandler(Of SomeForm)
Protected Overrides Function OnStartup(e As StartupEventArgs) As Boolean
SomeFormHandler = New MyFormHandler(Of SomeForm)
Return MyBase.OnStartup(e)
End Function
End Class
End Namespace
Add an Interface that defines the Actions (or Behaviors) that a Form must implement.
Here, the GetUsersList() method specifies that a Form that implements this Interface must return the instance of a child ListBox Control.
(To add an Interface, select Project -> Add -> New Item... and select the Interface template. Name the file IFormHandler)
Extend this Interface as needed, to add more Methods or Properties that define actions and behaviors.
Public Interface IFormHandler
Function GetUsersList() As ListBox
End Interface
A Form that implements the IFormHandler Interface implements and exposes the GetUsersList() method, which returns the instance of a ListBox Control (named usersList here)
There's nothing else to do with this Form, the control is handed over to the MyFormHandler object that is initialized with this Type.
Public Class SomeForm
Implements IFormHandler
Public Sub New()
InitializeComponent()
End Sub
Public Function GetUsersList() As ListBox Implements IFormHandler.GetUsersList
Return Me.usersList
End Function
End Class
Now, to show SomeForm, you can use the MyFormHandler class object show below.
' Set the Owner if called from another Form
My.Application.SomeFormHandler.Show(Me)
' Or without an Owner
My.Application.SomeFormHandler.Show()
To close SomeForm, you can either use its handler:
My.Application.SomeFormHandler.Close()
or close it as usual:
[SomeForm Instance].Close()
If MyFormHandler determines that the instance of SomeForm has been disposed, it creates a new one when you call its Show() method again later.
To update the ListBox Control of SomeForm, use the public methods exposed by the MyFormHandler class:
' Add a new element
My.Application.SomeFormHandler.UpdateUsersList(UpdateType.AddElement, "Some Item")
' Remove an element
My.Application.SomeFormHandler.UpdateUsersList(UpdateType.RemoveElement, "Some Item")
' Replace an element
My.Application.SomeFormHandler.UpdateUsersList(UpdateType.ReplaceElement, "New Item", "Some Item")
' Clears the ListBox
My.Application.SomeFormHandler.ClearUsersList()
All these actions generate an event that you can subscribe to when needed.
See also the example that shows how to raise a custom event when the ListBox raises one of its stardard events; SelectedIndexChanged is handled here.
See the implementation of MyFormHandler.
Generic Form handler:
A Form needs to implement the IFormHandler Interface for the MyFormHandler class to accept it as valid.
You can of course extend the Interface, to add more Actions, or build a MyFormHandler class object that uses a different Interface, or more than one.
Public Class MyFormHandler(Of TForm As {Form, IFormHandler, New})
Implements IDisposable
Private formObject As TForm
Private IsInstanceSelfClosing As Boolean = False
Public Event UsersListUpdate(item As Object, changeType As UpdateType)
Public Event UsersListIndexChanged(index As Integer)
Public Sub New()
InitializeInstance()
Dim lstBox = formObject.GetUsersList()
AddHandler lstBox.SelectedIndexChanged, AddressOf OnUsersListIndexChanged
End Sub
Private Sub InitializeInstance()
formObject = New TForm()
AddHandler formObject.FormClosing, AddressOf OnFormClosing
End Sub
Private Sub OnFormClosing(sender As Object, e As FormClosingEventArgs)
IsInstanceSelfClosing = True
Dispose()
End Sub
Public Sub UpdateUsersList(updateMode As UpdateType, newItem As Object, Optional oldItem As Object = Nothing)
If newItem Is Nothing Then Throw New ArgumentException("New Item is null")
Dim lstBox = formObject.GetUsersList()
Select Case updateMode
Case UpdateType.AddElement
lstBox.Items.Add(newItem)
Case UpdateType.RemoveElement
lstBox.Items.Remove(newItem)
Case UpdateType.ReplaceElement
If oldItem Is Nothing Then Throw New ArgumentException("Replacement Item is null")
Dim index = lstBox.Items.IndexOf(oldItem)
lstBox.Items.Remove(oldItem)
lstBox.Items.Insert(index, newItem)
Case Else : Return
End Select
RaiseEvent UsersListUpdate(newItem, updateMode)
End Sub
Public Sub ClearUsersList()
formObject.GetUsersList().Items.Clear()
End Sub
Private Sub OnUsersListIndexChanged(sender As Object, e As EventArgs)
RaiseEvent UsersListIndexChanged(DirectCast(sender, ListBox).SelectedIndex)
End Sub
Public Sub Show(Optional owner As IWin32Window = Nothing)
If formObject Is Nothing OrElse formObject.IsDisposed Then InitializeInstance()
If formObject.Visible Then
formObject.WindowState = FormWindowState.Normal
formObject.BringToFront()
Else
formObject.Show(owner)
End If
End Sub
Public Sub Close()
If formObject IsNot Nothing AndAlso (Not formObject.IsDisposed) Then
RemoveHandler formObject.FormClosing, AddressOf OnFormClosing
IsInstanceSelfClosing = False
Dispose()
End If
End Sub
Public Sub Dispose() Implements IDisposable.Dispose
Dispose(True)
GC.SuppressFinalize(Me)
End Sub
Protected Overridable Sub Dispose(disposing As Boolean)
If disposing Then
If formObject Is Nothing OrElse formObject.IsDisposed Then Return
Dim lstBox = formObject.GetUsersList()
RemoveHandler lstBox.SelectedIndexChanged, AddressOf OnUsersListIndexChanged
RemoveHandler formObject.FormClosing, AddressOf OnFormClosing
If Not IsInstanceSelfClosing Then formObject.Close()
IsInstanceSelfClosing = False
End If
End Sub
End Class
Enumerator used in MyFormHandler:
Public Enum UpdateType
AddElement
RemoveElement
ReplaceElement
End Enum

Visual Basic: How do I make a Global List of a custom Class?

I think I'm missing an important idiosyncrasy of Visual Basic. I mostly just know C++, so I don't understand the need for the Dim keyword, and the As New keyword. However, I am familiar with the New keyboard in C++, which is used when you use a pointer.
So in Visual Basic are all variables pointers? What's going on here?
I want to make a custom Class. And have a list or array of say, four of them, and for them to be Globally accessible all throughout my program. Do I declare them in my Form Class? My program is just the one Form.
Ok, so I've got the list to exist, but only in the button click sub routine.
How do I make my List of Clocks Global?
Public Class MyClock
Public elapsedtime As New TimeSpan(0, 0, 0, 0, 0)
Public active As Boolean
Public Sub New()
elapsedtime = New TimeSpan(0, 0, 0, 0, 0)
End Sub
Public Function Display()
Return elapsedtime.ToString
End Function
Public Sub Start()
active = True
End Sub
Public Sub Stopclock()
active = False
End Sub
Public Sub Toggle()
If (active = True) Then
active = False
Stopclock()
Else
active = True
Start()
End If
End Sub
End Class
Public Class Form1
Dim ticincrement As New TimeSpan(0, 0, 0, 0, 100)
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
End Sub
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
Dim ClockList As New List(Of MyClock)()
ClockList.Add(New MyClock)
ClockList.Add(New MyClock)
ClockList.Add(New MyClock)
ClockList.Add(New MyClock)
Console.WriteLine(ClockList.Count)
Console.WriteLine(ClockList(0).elapsedtime)
End Sub
End Class
Ok, the “new” keyword is just a short cut that allows you to declare the variable (it is a pointer) and create + initialize an instance of the class being assigned to that variable.
The following two are same.
Dim TestClock as MyClock
TestClock = New MyClock
And
Dim TestClock as New MyClock.
However, ONE very significant difference in the above two code snips should be noted:
In the 2nd example in which we declare using “new”, the new instance of the object (class) is thus created.
Often, we want to control WHEN the instance of the class (and the new (initialize) event of the class will run. (So don’t use new in the var define).
The other issue of that WHEN you leave out the NEW keyword, then the class variable is essentially a pointer to the class, but one that does not yet exist.
Eg this:
Dim pbar1 As New Pbar
Dim pbar2 As Pbar
pbar2 = pbar1
So, pbar2 we NEVER created an instance of the class, so it really is a pointer. So, from any code that follows, I can use pbar1, or pbar2 – they are pointing to and are the same instance of the one class we created with “new”.
This concept is important, since say if you going to pass a class to another form, then you could/would declare the class without new keyword as global scoped to that form.
Note that you should declare the variable as “public” if you want other forms/code to use that variable.
Eg:
Imports System.Threading
Public Class Form1
Dim MyPbar As Pbar
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Etc. etc.
And if public global, we would use:
Imports System.Threading
Public Class Form1
Public MyPbar As Pbar <--- pubic scope - can use outside of form
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Etc. etc.
Now
Then “any” place else in the project, you can go:
Form1.MyPbar.Min = 1
Form1.MyPbar.Max = 10
So, declaring as “public” will give you global scope. But you STILL must qualify the var by the form that variable resides in.
However, the scope is still limited to form that MUST be open. If that form is closed or goes out of scope, then of course you can’t reference that form in other forms/code.
What amount “many” forms, and wanting true global scope var?
A number of ways exist, but most easy is to add a standard code module to your project. So add a "module" as opposed to a "class". In that standard code module, you can place common routines (functions/subs) that you want for the whole application. So this approach is nice, since you don’t have to create an instance of that code module (it not consider class). It is just a standard “library” of code where you can shove in a bunch of routines. This is a carryover idea and concept from VB6, or VBA, but it really is nice.
And any public var declared in such modules are scoped appcation wide global.
(If using “dim”, then scope is only to that module).
So, if we add a code module we get this:
Module Module1
Public GlobalPbar As New Pbar
Public Sub Test()
MsgBox("test")
End Sub
End Module
So in place of “dim” I used “public” since I want use of this var outside of “module1”.
So for global scoped functions, subs and variables (including pointers to class vars)?
Simply create (add) to your project a standard code module. Some even often create/add a code module called MyGlobals, and they don’t even place any sub/functions, but just a list of “public” variables which of course become scoped to the whole application.
So in summary:
Declaring a class var without “new” creates a pointer to an instance of a given class. (And in this case the pointer is nothing - the object does not exist yet)
You can assign an existing instance of a class to the above declared variable – it works like a pointer. You have to use the new keyword in code to create that instance.
You can also for convenience sake combine the two above steps into one declare with the "new" keyword. This is often done, and of course with “overloading”, we can supply parameters when you do this.
You can create a global var in the standard code module. You can also create the “list of” variable in that code module, and it again will also be global scoped and not tied to one form, and you not be tied or limited to any instance of a form being open to use such global vars. And you don't have to qualify the sub or vars with module1, they are scoped global.
Comments and explanations are in-line.
Public Class Form2
Private ClockList As New List(Of MyClock) 'This can be seen anywhere in the Form code.
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
'Add items to list with and without setting properties
ClockList.Add(New MyClock(New TimeSpan(1, 13, 22, 7), True))
ClockList.Add(New MyClock)
ClockList.Add(New MyClock(New TimeSpan(0, 11, 3, 6), False))
ClockList.Add(New MyClock(New TimeSpan(3, 7, 11, 433), True))
Debug.Print(ClockList.Count.ToString)
Console.WriteLine(ClockList(0))
'The default properties will print for the second item in the list
Console.WriteLine(ClockList(1))
Console.WriteLine(ClockList(2))
Console.WriteLine(ClockList(3))
Console.WriteLine("Values for the second item in list after properties set")
'Setting properties of the second item in list
ClockList(1).active = False
ClockList(1).elapsedtime = New TimeSpan(14, 7, 22, 34)
Console.WriteLine(ClockList(1))
End Sub
End Class
Public Class MyClock
'TimeSpan(days,hours,minutes,seconds,milliseconds)
'There is no need to set default values for the TimeSpan or call New
'The TimeSpan is a Structure made up of Integers so the default values
'are automatically set
Public Property elapsedtime As TimeSpan
Public Property active As Boolean
Public Sub New() 'Add back the default constructor
'unnecessary to assign elapsedTime because it is already set to (0,0,0,0,0)
End Sub
Public Sub New(ETime As TimeSpan, act As Boolean)
elapsedtime = ETime
active = act
End Sub
Public Function Display() As String
Return elapsedtime.ToString
End Function
'Public Sub Start()
' active = True
'End Sub
'Public Sub Stopclock()
' active = False
'End Sub
Public Sub Toggle()
active = Not active
'If active = True Then
' active = False
'You just set active to False, why would you call a Sub to set it to False?
'Stopclock()
'Else
'active = True
'You just set active to True, why would you call a Sub to set it to True?
'Start()
'End If
End Sub
Public Overrides Function ToString() As String
Return $"Elapsed Time is {elapsedtime.Days} Days, {elapsedtime.Hours} Hours, {elapsedtime.Minutes} Minutes, {elapsedtime.Seconds} Seconds, {elapsedtime.Milliseconds} Milliseconds and Active is {active}"
End Function
End Class
Results displayed in Immediate Window
4
Elapsed Time is 1 Days, 13 Hours, 22 Minutes, 7 Seconds, 0
Milliseconds and Active is True
Elapsed Time is 0 Days, 0 Hours, 0 Minutes, 0 Seconds, 0 Milliseconds
and Active is False
Elapsed Time is 0 Days, 11 Hours, 3 Minutes, 6 Seconds, 0 Milliseconds
and Active is False
Elapsed Time is 3 Days, 7 Hours, 18 Minutes, 13 Seconds, 0
Milliseconds and Active is True
Values for the second item in list after properties set
Elapsed Time is 14 Days, 7 Hours, 22 Minutes, 34 Seconds, 0
Milliseconds and Active is False

Calling functions outside class

what is the correct way to call function outside the class, below code is also working
tried an alternate way by using delegate but couldn't figure out to pass function with parameters from Form class to classname so that form function can be called.
Public class form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
dim cl as new classname
cl.run()
end sub
function testmsg(txt as string)
msgbox(txt)
end function
end class
public class classname
public sub run()
txt = "xyz"
if(condition = true) then call form1.testmsg(byref txt as string)
end sub
end class
You can at any time, and in any place, and from a form, a class object, or even just standard vb module call/use a function (or in your case, it should be a sub).
Just mark any routine (sub/function) in the form as public.
eg:
Public function testmsg(txt as string)
msgbox(txt)
end function
NOw, in any other form, class or in fact any place you have code, you can thus go:
FormA.TestMsg("hi from form B")
so, there are no restrictions here. And any form wide scoped variables marked as public can also be used:
eg:
Public Class FormA
Public Zoo As String
Public Function TestMsg(txt As String)
MsgBox(txt)
End Function
Public Sub ShowZoo()
MsgBox("value of zoo = " & Zoo)
End Sub
End Class
So above is FormA
Now, any code from any ohter form, class or whatever can do this:
FormA.TestMsg("hi from form B")
FormA.Zoo = "this is zoo value"
FormA.ShowZoo()
So, just mark any variable as public (it in effect becomes a public property of that form).
And, just mark any function/Sub as pubic (it in effect becomes a public "method" of that form.

How to serialize a List(of Object) in VB.NET?

I have a class Player that I use to create a List(Of Player). I need to save it when the application closes. In Windows Forms, I would just serialize, but that's no longer possible in UWP, so I had to Google for a few dozen of hours and I finally stumbled upon Microsoft.Toolkit.Uwp, then Newtonsoft.Json, but I fail miserably to use them. I need your help!
Let's say I have a small class :
Dim Name As String
Dim Score As Double
Public Class Player
<JsonConstructor()>
Public Sub New(Name As String, Score As Double) ' New with score
Me.Name = Name
Me.Score = Math.Max(1, Score)
End Sub
End Class
Public Overrides Function ToString() As String ' ToString
Return $"{Name} [{Score}]"
End Function
How do I successfully read and write a List(Of Player)?
' Loading MainPage.xaml
Private Sub MainPage_Loading() Handles Me.Loading
ReadAsync()
MainFrame.Margin = New Thickness(0)
Window.Current.Content = MainFrame
MainFrame.Navigate(GetType(PlayerList), Players)
End Sub
' Read
Private Async Sub ReadAsync()
Players = JsonConvert.DeserializeObject(Of List(Of Player))(Await FileIO.ReadTextAsync((Await StorageFolder.CreateFileAsync("players.json", CreationCollisionOption.OpenIfExists))))
If Players Is Nothing Then
Players = New List(Of Player)
WriteAsync()
End If
End Sub
' Write
Public Shared Async Sub WriteAsync()
Await FileIO.WriteTextAsync(Await StorageFolder.CreateFileAsync("players.json", CreationCollisionOption.ReplaceExisting), JsonConvert.SerializeObject(Players, Formatting.Indented))
End Sub
' Loading PlayerList.xaml
Protected Overrides Sub OnNavigatedTo(e As NavigationEventArgs)
ListBoxPlayers.Items.Clear()
Players = e.Parameter
For Each Player In Players
ListBoxPlayers.Items.Add(Player)
Next
End Sub
' Adding a new player in the interface
Private Sub ButtonAddPlayer_Click(sender As Button, e As RoutedEventArgs) Handles ButtonAddPlayer.Click
' ...
' Commit
MainPage.Players.Add(New Player(TextBoxName.Text))
ListBoxPlayers.Items.Add(MainPage.Players(MainPage.Players.Count - 1))
MainPage.WriteAsync()
End Sub
So this is all confusing. When I add a player trough the interface, it enters my ListBox like normal. However, when I close the application and I re-open it, I get a handful of empty objects.
I did some angry testing to know more about my problem, turns out I'm not serializing at all, but I probably am deserializing correctly.
I found it, turns out it's in my class Player.
What I used :
Dim Name As String
Dim Score As Double
What worked :
Public Name As String
Public Score As Double
What I should have done :
Public Property Name As String
Public Property Score As Double
I was taught to never set variables as "public" when coding in Java, and I didn't know that Property existed in Visual Basic.

Event Raised in an Object also fires in a separate Object of same Class?

VB NET 2010, Framework 3.5
Trying to understand why this works. I create two objects from the the same Class1. GlobalClass1 with Global Scope and LocalClass1 with Module Scope.
In UControl's Load event I set LocalClass1 = GlobalClass1 From this point on anytime I change value of GlobalClass1.TestProperty the property value is also updated in LocalClass1. The Events in LocalClass1 are triggered when GlobalClass1 events fire.
This is the result I was looking for => being able to have a Global Object's events fire in several other Class Modules and User Controls.
I don't quite understand why simply setting the Local Object = Global Object causes the Local Object to automatically update it's property values when the Global Object properties are updated or why the Local Events automatically fire when the Global Object is raising the event?
Module Module1
Public WithEvents frm As New MainForm
Public WithEvents GlobalClass1 As New Class1
Public Sub Main()
frm.Init()
frm.ShowDialog()
End Sub
End Module
Public Class MainForm
Private uiUserControl As UControl
Public Function Init() As Boolean
uiUserControl = New UControl
uiUserControl.Location = New System.Drawing.Point(60, 80)
Me.Controls.Add(uiUserControl)
Return True
End Function
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
Static count As Integer
GlobalClass1.TestProperty = count.ToString ' This line propagates to the Private Local LocalClass1 and cause it's event to fire??
count += 1
End Sub
End Class
Public Class UControl
Private WithEvents LocalClass1 As New Class1
Private Sub UControl_Load(sender As Object, e As System.EventArgs) Handles Me.Load
LocalClass1 = GlobalClass1
End Sub
Private Sub LocalClass1_TestPropertyChanged() Handles LocalClass1.TestEvent
Me.TextBox1.Text = LocalClass1.TestProperty 'This Event fires when events are raised in the other object => GlobalClass1??
End Sub
End Class
Public Class Class1
Public Event TestEvent()
Private _testProperty As String
Public Property TestProperty() As String
Get
Return _testProperty
End Get
Set(ByVal value As String)
_testProperty = value
RaiseEvent TestEvent()
End Set
End Property
End Class
The class instances (objects) are both referencing the same memory space allocated to them on the heap.
from comments:
The problem is with this line: LocalClass1 = GlobalClass1
They started out as different objects but then you made them refer to the same thing. Object references - or reference types - work differently than value types like integer:
Dim x As Int32
Dim y As Int32 = 42
x = y
As value types, the value of y is assigned to x. A reference type is essentially a wrapper or alias for a pointer. Your assignment code therefore replaced the original pointer to a New Class1, with the pointer already assigned to GlobalClass1
Read more about Value vs Reference types at MSDN