When ever I change an attribute of a class, the window won't open - vb.net

When ever I try to change an attribute in the load method of a class I created, it won't let me open it. If I leave the load method blank or put anything else there, it works fine.
Public Class Main
'SHIPS
Dim AirCraftCarrier As Ship
Private Sub Main_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
AirCraftCarrier.name = "ACC" ' These won't work
AirCraftCarrier.SetAttributes("ACC", AirCraftCarrier_image, 5, "vertical", new_pos, False, False) ' If I leave it blank or keep anything else here, it opens fine.
End Sub
End Class
Public Class Ship
Public name As String
Public image As PictureBox
Public direction As String
Public selection As Boolean
Public placed As Boolean
Public location(2) As Integer
Public Sub SetAttributes(ByVal name1 As String, ByVal image1 As PictureBox, ByVal length1 As Integer, ByVal direction1 As String, ByVal location1 As Array, ByVal selected1 As Boolean, ByVal placed1 As Boolean)
name = name1
image = image1
direction = direction1
selection = selected1
placed = placed1
location(0) = location1(0)
location(1) = location1(1)
End Sub
End Class

First changes to Ship. Classes tend to use Properties rather than fields:
Public Class Ship
Public Property name As String
Public Property image As PictureBox ' bad name; Net has an Image class
' etc
' set essential props via the constructor:
Public Sub New(sName As String, picB As PictureBox)
name = sName
image = picB
End Sub
Then in main for creating it:
Public Class Main
Dim AirCraftCarrier As Ship ' this is just a variable declaration
Private Sub Main_Load(ByVal sender As System.Object,
ByVal e As System.EventArgs) Handles MyBase.Load
' Create an instance:
AirCraftCarrier = New Ship("ACC", frm.PicBoxName)
' set other properties
AirCraftCarrier.Direction = "SSW"
AirCraftCarrier.Foo = "Bar"
End Sub
End Class
With a constructor you can pass the essential information, like the unique name to the class when you create it. This is used instead of the SetAttributes sub.

Related

How value from different class/form can be changed without ByRef

Let's assume following example below:
When I call Form2 from Form1 and pass _name of Form1 value. When I show Form1's _name = Alex? I didn't change pname in Form2 and constructor doesn't contains ByRef.
Example code:
Public Form1
Public _name as String
Sub New
_name = "John"
Dim bla as New Form2(_name)
'now _name=Alex !!
End Sub
End Class
Public Form2
Property _name2 as String
Sub New(pname as String) 'no ByVal !!
_name2 = pname 'even if would be ByVal no pname changed !
_name2 = "Alex"
End Sub
End Class
Why is that happening?
Use Shared in variable _name:
Class Form1
Public Shared _name As String
Public Sub New()
_name = "John"
End Sub
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
' Message "John"
MessageBox.Show(_name)
Dim bla As New Form2()
bla.Show()
' Message "Alex"
MessageBox.Show(_name)
End Sub
End Class
Public Class Form2
Property _name2 As String
Sub New()
_name2 = "Alex"
Form1._name = _name2
End Sub
Private Sub Form2_Load(sender As Object, e As EventArgs) Handles MyBase.Load
' message Alex
MessageBox.Show(_name2)
' message Alex
MessageBox.Show(Form1._name)
End Sub
End Class
Or
When the modifier is not entered in the signature of a constructor (method), the default is byVal. If you want to change the value of the variable in form2 you must inform byref in the form2 constructor signature:
Sub New (byref _name as String)
To change the underlying value of an argument you must use the ByRef modifer:
Specifies that an argument is passed in such a way that the called procedure can change the value of a variable underlying the argument in the calling code.
This differs slightly from ByVal:
Specifies that an argument is passed in such a way that the called procedure or property cannot change the value of a variable underlying the argument in the calling code.
By not specifying a modifier in VB.NET the compiler by default will use ByVal.
It would be good to note here that although VB.NET uses ByVal by default if not specified, VBA does not and instead by default uses ByRef. Beware of this should you ever port code from one to the other.
Furthermore you are changing name2 when instead you should be changing pname if you want to change the underlying value.
Have a look at the following code based on your example:
Public Class Form1
Private _name As String
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
_name = "John"
Dim bla As New Form2(_name)
bla.Show()
Debug.WriteLine(_name)
End Sub
End Class
Public Class Form2
Private Property _name2 As String
Public Sub New(ByRef pname As String)
InitializeComponent()
_name2 = pname
pname = "Alex"
End Sub
End Class
Before passing the value to Form2 the name is "John":
At this point I am changing the value of pname to "Alex":
Note that although I have changed the value of pname To "Alex", _name2 is still set to "John".
Notice how the value of _name changes to "Alex" because of the change made to pname:
I'm not sure what it is you're trying to achieve here but hopefully this example gives you a better understanding. The alternative way would be to use a shared variable as explained in the other answer.

VB.NET Class with no constructor (no new instance can be declared)

I'm making my own message box class (called MessageBoxC, whatever), and like System.Windows.Forms.MessageBox, I want to make my class with no constructors and no possibility to declare a new instance of it.
E.g.:
Public Class MessageBoxC
Public Overloads Sub Show(ByVal message As String)
Me.Message = message
ProcessData() '(*)
Me.ShowDialog()
End Sub
End Class
Public Class Form1
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
System.Windows.Forms.MessageBox.Show("Hello World!") 'works fine
MessageBoxC.Show("Hello World!") 'works fine
Dim msgBox As New System.Windows.Forms.MessageBox 'and you'll get an error message here (**)
Dim msgBoxC As New MessageBoxC 'no error message
End Sub
End Class
(*) Not important. It just calculates text size (width and height in pixels) to correct form size if needed and the corresponding label gets value of Me.Message property.
(**) This one is what I mean. You cannot make a new instance of a MessageBox class, you'll get following error-message: "Type System.Windows.Forms.MessageBox has no constructors."
Well, my class has also no constructors, but it's possible to declare an instance of it. What's the trick here?
Thanks a lot!
Solved. Thanks to OneFineDay.
Public Class MessageBoxC
Private Sub New()
'Empty
End Sub
Public Overloads Shared Function Show(ByVal message As String) As System.Windows.Forms.DialogResult
Return Show(message, Constants.MyAppName, Constants.messageTitle, MessageBoxCButtons.OK, MessageBoxCIcon.Undefined)
End Function
Public Overloads Shared Function Show(ByVal message As String, _
ByVal caption As String, _
ByVal title As String, _
ByVal buttons As Library.MessageBoxCButtons, _
ByVal icon As Library.MessageBoxCIcon) As System.Windows.Forms.DialogResult
Dim msgBoxC As New CBox(message, caption, title, buttons, icon)
msgBoxC.ShowDialog()
Return msgBoxC.DialogResult
End Function
Private Class CBox
Inherits System.Windows.Forms.Form
Sub New(ByVal message As String, _
ByVal caption As String, _
ByVal title As String, _
ByVal buttons As Library.MessageBoxCButtons, _
ByVal icon As Library.MessageBoxCIcon)
MyBase.New()
InitializeComponent()
Me.Message = message
Me.Text = caption
Me.Title = title
Me.Buttons = buttons
Me.Icon64 = icon
Me.OptimizeMe()
End Sub
End Class
End Class
Public Class Form1
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
Dim dialogResult As New DialogResult
dialogResult = MessageBoxC.Show("This is a simple message.")
MessageBox.Show(dialogResult.ToString)
End Sub
End Class
If you don't declare any constructors, a default constructor is automatically created (this is a public constructor with no parameters).
To prevent anyone creating an instance of your class, you can create a private constructor, like so:
Public Class MessageBoxC
Private Sub New()
' Prevents anyone creating an instance of this class.
End Sub
End Class
Note that your Show method will need to be declared Shared, otherwise you won't be able to call it. In fact, it would need to be Shared, even with the code you provided.
Here is one way to hide the constructor - mainly because the class in question is not accessible.
Public Class Form1
Private Sub meLoad() Handles Me.Load
'Usage
FooBar.Show("Hi")
End Sub
'...
End Class
Public Class FooBar
Private Sub New()
End Sub
Public Shared Sub Show(message As String)
Dim mbc As New MessageBoxC(message)
mbc.ShowDialog()
End Sub
'MessageBoxC is not exposed outside of Foobar which is the entry point
Private Class MessageBoxC : Inherits Form
'define cTor's as needed
Public Sub New(message As String)
Me.Text = message
End Sub
'define content
End Class
End Class

Retrieve a object from a list of objects in visual basic and use it to fill text/combo boxes

I have a class as seen below:
Public Class parameters
Public Property test As String
Public Property test_type As String
Public Property user_test_name As String
Public Property meas As String
Public Property spec As String
...etc
End Class
I make a list of objects that I import from a csv somewhere. The user_test_name's from the list gets sent to a list box:
For Each parameters In param
' MsgBox(parameters.user_test_name)
ListBox1.Items.Add(parameters.user_test_name)
Next
now when the user selects something from the list i want the rest of the properties of that particular user_test_name object to populate in certain text/combo boxes in the application. Here is how I grab what is selected.
Private Sub ListBox1_SelectedIndexChanged(ByVal sender As System.Object,
ByVal e As System.EventArgs) Handles ListBox1.SelectedIndexChanged
Dim selected_name As String = ListBox1.SelectedItem()
' MsgBox(selected_name)
find_object_by_user_test_name(selected_name)
End Sub
Now i'm having difficulty finding the object with the selected_name from the list and using its properties to fill the text.combo boxes. I tried the following to no success:
Public Sub find_object_by_user_test_name(ByVal description)
MsgBox(description)
Dim matches = From parameters In param
Where parameters.user_test_name = description
Select parameters
' MsgBox(matches)
' MsgBox(matches.user_test_name)
TextBox1.Text = matches.test
TextBox2.Text = matches.test_name
etc,,, on and on
' populate_area(matches)
End Sub
Instead of adding the name (a string) to the ListBox, add your actual INSTANCE to it.
First, override ToString() in your class so that it displays properly in your ListBox:
Public Class parameters
Public Property test As String
Public Property test_type As String
Public Property user_test_name As String
Public Property meas As String
Public Property spec As String
Public Overrides Function ToString() As String
Return user_test_name
End Function
End Class
Next, add each instance to the ListBox:
For Each parameters In param
ListBox1.Items.Add(parameters)
Next
Now, the SelectedIndexChanged() event, you can cast the SelectedItem() item back to parameters and you already have everything at your disposal:
Private Sub ListBox1_SelectedIndexChanged(ByVal sender As System.Object,
ByVal e As System.EventArgs) Handles ListBox1.SelectedIndexChanged
If ListBox1.SelectedIndex <> -1 Then
Dim P As parameters = DirectCast(ListBox1.SelectedItem, parameters)
' ... do something with "P" ...
Debug.Print(P.user_test_name & " --> " & P.test)
End If
End Sub
If the user_test_names are unique, it may be easier to use a dictionary and retrieve the objects that way.
Dim params As New Dictionary(Of String, parameters)
params.add(MyParameterObject.user_test_name, MyParameterObject)
Then
Private Sub ListBox1_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ListBox1.SelectedIndexChanged
Dim selected_name As String = ListBox1.SelectedItem()
Dim selected_param as parameters = params(selected_name)
End Sub
Something like this should do it:
Public Sub find_object_by_user_test_name(ByVal description As String)
' assuming param is your list of parameter objects
For Each p In param
If p.user_test_name = description Then
TextBox1.Text = p.test
TestBox2.Text = p.test_name
...
Exit For
End If
Next
End Sub
A few notes about your code. First, you can't allow two objects to have the same user_test_name. Second, you can't use parameters as a variable name if you already have a class called parameters in your current namespace (which you do).
There is a simpler solution than any of these--just do the following:
Dim i as Integer = ListBox1.SelectedIndex
Then you can use i as an index to your original list of objects.

When can I access a form's members?

At first I tried this:
Public Class frmWait
Public Sub New(ByVal uWindowText As String, ByVal uInfoText As String)
Me.Text = uWindowText
Me.lblInfoText.Text = uInfoText
End Sub
End Class
But when I initiated the form like this
Dim wait As New frmWait("blah", "blah")
wait.Show()
... it told me "NullReference Exception" at this line:
Me.lblInfoText.Text = uInfoText
Settings the form's text worked fine.
Okay, I subspected the label was just not created yet when I tried to set the text.
Then I tried the following. I stored the texts in a variable and wanted to set them when the controls have been created. I thought "Form_Load" was a good event for that:
Public Class frmWait
Private m_sWindowText As String = ""
Private m_sInfoText As String = ""
Public Sub New(ByVal uWindowText As String, ByVal uInfoText As String)
'we can not set the texts right away because lblInfo does not seem to exist yet
m_sWindowText = uWindowText
m_sInfoText = uInfoText
End Sub
Private Sub frmWait_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Me.Text = m_sWindowText
Me.lblInfoText.Text = m_sInfoText
End Sub
End Class
But it threw the same error.
Ehhhhh, when exactely can I set the control's text?
Did I make any beginner's mistake?
Don't delete what the designer does :) It's trying to help you. When you Create the
Public Sub New(...)
on a form, it will automatically put in :
Public Sub New()
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
End Sub
The InitializeComponent() is required to get the form ready for you to work with it.
Looks like you are missing the InitializeComponents call:
Public Sub New(ByVal uWindowText As String, ByVal uInfoText As String)
InitializeComponents()
m_sWindowText = uWindowText
m_sInfoText = uInfoText
End Sub
The method call loads all of the controls that were created using the designer. Without that call, your form is empty.

Bind a Class Property that returns a list to a DataGridViewComboBoxColumn

I have a file name that is found at multiple paths. I want to present this data to the user in the format of a DGV. I have a DGV with one text box column for the name, and another combobox column for the paths. I am having trouble getting the combobox column to bind to the property of the class that returns the paths.
Any help would be much appreciated.
Public Class fileTest
Public Property FileName As String
Public Property Paths As String()
Public Sub New(ByRef _name As String, ByVal _paths As String())
Me.FileName = _name
Me.Paths = _paths
End Sub
End Class
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim fileList As New BindingList(Of fileTest)
fileList.Add(New fileTest("TEST", {"ABC", "123"}))
Me.DataGridView1.AutoGenerateColumns = False
Me.DataGridView1.DataSource = fileList
Me.DataGridView1.Columns("FileName").DataPropertyName = "FileName"
CType(Me.DataGridView1.Columns("Paths"), DataGridViewComboBoxColumn).DataPropertyName = "Path"
End Sub
DataGridViewComboBoxColumn is horrible. HORRIBLE.
We eventually gave up using it and now just float a standard Combobox over the grid.