Adding Objects with Display Text to ComboBox and Selecting Them - vb.net

First it is worth it to note that I am very new to Visual Basic. I have created a win forms project in Visual Studio 2012 in the Visual Basic Language.
Given the below code, I want to use a combobox named cmbChoose to select from 4 options. These options will be listed in the combobox as:
"Problem 1"
"Problem 2"
"Problem 3"
"Problem 4"
When a user changes the index of cmbChoose, I would like the class object associated with that index to be set to a parent class object to get polymorphic behavior. A flow of this might be:
User selects "Problem 1".
Parent object problem is set to the class object stored at the index of "Problem 1". This object will be problem1 which is created at the top of the class.
User performs actions, problem1 is the current subclass executing functions
User selects "Problem 3".
Parent object problem is set to the class object stored at the index of "Problem 1". This object will be problem3 which is created at the top of the class.
It seems very simple, and I've read on several posts on stackOverflow to try to get the syntax correct, but I'm doing something wrong. I've made sure the combobox can "Use data bound items", and I've tried to set the DataSource, DisplayMember, and ValueMember in different ways. I've tried to access the object stored at a index in different ways.
I do not want to use conditionals to choose the object, it must be the object at the index chosen.
Here is the code. Assume the Problem classes and subclasses are correctly coded (they are). The functions that will need to be changed/implemented correctly are:
Frm_Base_Load() *or another appropriate function to load the combobox
cmbChoose_SelectedIndexChanged()
Public Class Frm_Base
Private problem As Problem
Private problem1 As Problem1 = New Problem1()
Private problem2 As Problem2 = New Problem2()
Private problem3 As Problem3 = New Problem2()
Private problem4 As Problem4 = New Problem2()
Private Sub btnQuit_Click(sender As Object, e As EventArgs) Handles btnQuit.Click
End
End Sub
Private Sub btnClear_Click(sender As Object, e As EventArgs) Handles btnClear.Click
lstTable.Items.Clear()
End Sub
Private Sub btnDoWhile_Click(sender As Object, e As EventArgs) Handles btnDoWhile.Click
problem.DoWhile()
End Sub
Public Sub btnDoUntil_Click(sender As Object, e As EventArgs) Handles btnDoUntil.Click
problem.DoUntil()
End Sub
Public Sub btnForNext_Click(sender As Object, e As EventArgs) Handles btnForNext.Click
problem.Fornext()
End Sub
Private Sub Frm_Base_Load(sender As Object, e As EventArgs) Handles MyBase.Load
'Need to implement
'cmbChoose.DataSource = problem1
'cmbChoose.DisplayMember = "Problem 1"
'cmbChoose.ValueMember = 0
End Sub
Private Sub cmbChoose_SelectedIndexChanged(sender As Object, e As EventArgs) Handles cmbChoose.SelectedIndexChanged
'Need to change to set parent object 'problem' to sub object at current index
problem = cmbChoose.DataSource
End Sub
End Class

Alright, asuming your Classes are correct this is what you have to do:
In Form_Load:
First create list of Problem
Dim ProbList As New List(Of Problem)
Then add all problems to that List.
ProbList.Add(ProblemX)
Then create a binding source and add the list as datasource
Dim BSProblems As New BindingSource
BSProblems.DataSource = ProbList
Then add the Bindingsource to the combobox.
ComboBox.DataSource = BSProblems
Then add whatever display member you want (I have selected Name, you probably have something different).
ComboBox.DisplayMember = "Name"
Then, in your Problem class you would have to have a property called Name. You create a property like this:
Property Name As String
Notice how it does not say "Public Name..." since that doesn't work (this is a common mistake here).
Finally you have to fetch the Problem base class from SelectedIndexChanged:
problem = CType(ComboBox.SelectedItem, Problem)
Hope this helps you out. Note that the only reason I help you this much is because I had a hard time understanding this myself. Don't expect this kind of help in the future since it does not look like you have tried that many things before posting this question.

Related

How to access data from calling object in vb.net

I have a Window-Form 'caller' in vb.net containing a datagridview with a small overview table of certain objects, each with its own ID in the first column. Now, if a row is double clicked, i want to show a dialog 'edit', where one can edit many details of that row which i do not want in the overview table.
My approach is as follows: In the caller form i wrote this to call 'edit':
Private Sub dgdata_dbclick(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellMouseEventArgs) Handles dg_data.CellMouseDoubleClick
Dim f_edit As New edit
f_edit.ShowDialog(Me)
End Sub
That works fine.
However, in the called Form "edit" i need to check, which ID was selected and load this data from the database to edit it. I can access some data from the calling form 'caller' using e.g.
MsgBox(CType(Me.Owner, caller).Text)
to show the window title of 'caller'. However, i want to extract the currently selected ID in the datagridview or at least some variabhle containing it. In the caller form, this could be easily done by evaluating
dg_data.Item(0, selectedRow).Value.ToString
but i cannot access any relevant information in 'caller'. I have a public class with some global variables there but i cannot access them as well.
Probably my strategy to solve this problem is not the most clever approach? Basically, i want to open a very detailed edit window when someone clicks on a line in an overviewtable but simultaniously blocking the rest of the application as long as the edit window is open.
Thanks!
The idea is to pass the data to the second form. When you create an instance of the second form (my class is called Form2, yours is called edit) with the New keyword the Sub New is called on Form2.
Private Sub OpenEditDialog()
Dim f_edit As New Form2(32) '32 is the number you retrieve from your DataGridView
f_edit.ShowDialog(Me)
f_edit.Dispose()
End Sub
You pass the ID to Form2 and set a variable at Form level. You can then use the variable anywhere in Form2.
Public Class Form2
Private ID As Long
Public Sub New(SelectedID As Long)
InitializeComponent()
ID = SelectedID
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
MessageBox.Show(ID.ToString)
End Sub
End Class
You need to call InitializeComponent() so the controls will show up.
How do you usually get data into objects? You set a property or pass an argument to a method or constructor? Why should this be any different? Decide which you want to use and then write that code in your form. If it's required data, I would suggest a constructor. Just write this code in your form:
Public Sub New
and hit Enter. That will generate a little extra code automatically. You can then add a field to store the value, a parameter to the constructor and then assign the parameter to the field inside.
Thank you for pointing me to the correct route.
I solved it like this (which works fine and which is hopefully acceptable):
In the calling form:
Private Sub dgdata_dbclick(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellMouseEventArgs) Handles dg_data.CellMouseDoubleClick
Dim selectedRow As Integer = dg_data.CurrentCell.RowIndex
Dim f_edit As New edit
f_edit.edit(dg_data.Item(0, selectedRow).Value.ToString)
f_edit.ShowDialog(Me)
f_edit.Dispose()
End Sub
In the called form:
Public Sub edit(ByVal id As Long) 'Handles MyBase.Load
'Enter commands to prepare your form
End Sub

Get Object from a Collection to another form

In my second Form, I have a Collection of an Object which I add when I need.
When I want to access to the first Object in that Collection for example, from another Form. It returns me nothing: when I do form2.list.Count, I have 0. What I understood from this, is the Collection is Null.
But in the second form (the Form where I created that Collection), if I do form2.list.Count, I have the correct count and I have access to all the data.
I made sure that Collection was Public but still, I don't know where is the problem.
How can I solve this ?
Edit:
Public Class Form2
Public mycarlist As New carlist
Private Sub button1_Click(sender As Object, e As EventArgs) Handles button1.Click
dim mycar as car
'I have other textbox but for simplicity, I only put one
mycar = new car(Me.TextBox1.Text)
mycarlist.Add(mycar)
' Here everything works, I have the correct count and brand
Form1.TextBox1.Text = mycarlist.count
Form1.TextBox2.Text = mycarlist(0).brand
Me.Close()
End Sub
End Class
And it's from this Form (Form1) that I want to access to this list:
Public Class Form1
Private Sub testbt_Click(sender As Object, e As EventArgs) Handles tesbt.Click
Me.TextBox3.Text = Form2.mycarlist.Count
'For example a Property that I want to print
Me.TextBox4.Text = Form2.mycarlist(0).Brand
End Sub
Private Sub openform2_Click(sender As Object, e As EventArgs) Handles openform2.Click
Form2.Show()
End Sub
End Class
In the Form1, the TextBox1 returns me 0
And when the program will execute this line Me.TextBox2.Text = Form2.mycarlist(0).Brand, I have this error:
System.ArgumentOutOfRangeException from carlist.
Your assertion that the collection is null is incorrect because otherwise you'd receive a NullReferenceException to the effect of:
Run-time exception (line -1): Object reference not set to an instance of an object.
VB.NET does some funky stuff when it comes to accessing forms. My guess is that you're attempting to get the wrong instance of Form2 and VB.NET is creating a new instance of the Form behind the scenes.
Could you show how it is that you're creating Form2? It may be as simple as referencing the correct instance of the Form. E.g.:
Private frm2 As Form2 = New Form2()
' user adds item(s) to list
frm2.list.Count

DataListView with DataSource of ObservableCollection does not display newly added objects

Created form with a single button and a single DataListView.
Added this code to form:
Dim dummies As New ObservableCollection(Of Dummy)
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
dlvDummies.DataSource = dummies
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
dummies.Add(New Dummy(Now.ToLongTimeString()))
End Sub
Class Dummy
Public Property X As String
Sub New(x As String)
Me.X = x
End Sub
End Class
Ran the app, pressed the button. In the debugger, I can visibly see a new entry added to the ObservableCollection and correspondingly to the DataListView .Objects:
Item never appears in the GUI (Yes, the DataListView's sole column is already set up with the aspect name "X" at design time.)
This is actually a bare bones reproduction of the problem I'm having in a larger app. The answer given in https://stackoverflow.com/a/30157854/2112855 implies that this should "just work". Is this a defect, or user error on my part?
Replacing ObservableCollection(Of foo) with BindingList(Of foo) fixed, or rather worked around this.
I think, based on the discussion seen at https://sourceforge.net/p/objectlistview/discussion/812923/thread/ab0d6208/ that the accepted answer in https://stackoverflow.com/a/30157854/2112855 is faulty and should probably be edited.

Perform Load upon after click button

I am trying to use the panel and buttons to load 2 different forms along with entity framework and ado model stuff. I am trying to load the 2nd form this picture, using the codes running on the first form since they have the same table. but what happen is whenever I close the 2nd form and try to switch on the second user from this form(driverlist), I am still getting the results that I created before on the first user, I kinda think that the 2nd form is not being loaded although I put some code:
Private Sub DriverLicense_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim user_id As Integer = Driverlist.tbxUser_id.Text
Driverlist.db = New [Emme_Subic_Transport_Corporation_Payroll].EmmeSubicEntities
Driverlist.db.UserDetails.Where(Function(c) c.isDeleted <> 1 And c.Id = user_id).Load()
UserDetailBindingSource.DataSource = Driverlist.db.UserDetails.Local
If Driverlist.tbxUser_id.Text.Count < 1 Then
MessageBox.Show("Please Select an Employee ID First", "Information", MessageBoxButtons.OK, MessageBoxIcon.Information)
Drivertest.Panelswitch(Driverlist)
Else
Me.Show()
End If
End Sub
Private Sub DriverLicense_Activated(sender As Object, e As EventArgs) Handles Me.Activated
Dim user_id As Integer = Driverlist.tbxUser_id.Text
Driverlist.db = New [Emme_Subic_Transport_Corporation_Payroll].EmmeSubicEntities
Driverlist.db.UserDetails.Where(Function(c) c.isDeleted <> 1 And c.Id = user_id).Load()
UserDetailBindingSource.DataSource = Driverlist.db.UserDetails.Local
End Sub
I binded the 2nd form through other resources of data binding from the properties but still on the same resources as the first form. Im pretty new to this so please stop putting negatives on my questions. If you think I am bad at this, I know and I am sorry. by the way this is the code from the buttons and panel if that helps. Thanks everyone.
Sub Panelswitch(Panel As Form)
PanelControl.Controls.Clear()
Panel.TopLevel = False
PanelControl.Controls.Add(Panel)
Panel.Show()
End Sub
Private Sub Btntest_Click(sender As Object, e As EventArgs) Handles Btntest.Click
Panelswitch(Driverlist)
End Sub
Private Sub Btntest2_Click(sender As Object, e As EventArgs) Handles btntest2.Click
Panelswitch(DriverLicense)
End Sub
There are number of things I would avoid, just looking at your pictures, but that goes beyond your question.
Secondly, agreed with the comment, you should revise your question further (I see you tried, but still, it's neither complete or clear).
If I understand correctly, you have container PanelControl, which you fill either with a form DriverList or DriverLicence. I just want to make sure - are you sure you have your instances corectly set? Because I would expect that the switch would act only for displaying correct form, but should behave differently for the [persistent] list DriverList and DriverLicence, which should be probably a new instance every time you want to add a licence. But this code is not shown, just guessing the problem might be along those lines. There are quite few design possibilities, I guess.
Simplified, the point is:
Private Sub Btntest2_Click(sender As Object, e As EventArgs) Handles btntest2.Click
Dim DriverLicenceInstance as new DriverLicence
Panelswitch(DriverLicenseInstance)
End Sub
I also think, that you might have your binding set incorrectly for the 2nd form, the DriverLicence. I'm not proficient in .NET binding, but it seems to me that you declare the bindings as two separate things (comes from the copying the code?). But what you probably need to do is to use the same binding source for both parts. See here: A-Detailed-Data-Binding-Tutorial.

How do I pass an object to a default form instance

I understand its possible to open the "default instance" of a form in vb.net by calling NameOfTheForm.show()
How do I pass an object to the default form instance so i can work on the object and use it to populate the forms Text boxes?
I've tried to add a parameter to the frmNames New method but I'm not sure how then to open the form. The old style instantiate an object works:
Dim DetailsForm As New frmOrder(oOrder)
DetailsForm.Show()
But I'm used to using the :
frmOrder.show
syntax.
Should I use the top method or should I use the bottom method and have a public property on the form to accept the Object?
Have a missed a better method of doing this?
Thanks
Your calling method should use your first option
'Careful about declaring this in a sub, because when that sub ends, the form might get closed.
'It might be best to declare this as an instance var (aka form-level var)
Private DetailsForm As frmOrder
'this could go in an event handler, or anywhere
DetailsForm = New frmOrder(oOrder)
DetailsForm.Show()
You will need to add a constructor to your DetailsForm:
Private _oOrder as OrderType
Public Sub New(oOrder As OrderType)
'Best to save it to a private instance var and process it during Form_Load
_oOrder = oOrder
End Sub
Then when your Form_Load() runs, it can use your private instance var to fill your TextBoxes, like you want.
A second, but less eloquent approach would be to add a public property to the form and after you call .Show(), you can assign a value DetailsForm.OrderObject = oOrder, and then process the object that was passed-in.
The constructor approach is better because it can be "compiler checked"
If you really feel you must use default instance.
In Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Form2.myObject = New Coffee("Breakfast Blend", 7)
Form2.Show()
End Sub
In Form2
Public myObject As Coffee
Private Sub Form2_Load(sender As Object, e As EventArgs) Handles MyBase.Load
TextBox1.Text = myObject.Name
TextBox2.Text = myObject.ID.ToString
End Sub