I currently have 2 forms. 1 holds user data and is modifiable. The other is a display/read only form.
I am trying to pull data (tbUSI.text) from ReportSettings and pass it to Form1 and display it on my UserData.text control.
I have tried using public properties but to no avail. I would rather use public properties, since its cleaner. Here is the code im using to set the property:
Public Property UserSignedInto As String
Get
Return tbUSI.Text
End Get
Set(value As String)
End Set
End Property
Here is my code attempting to call that property on the main form (form1)
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
UserData.text = UserSignedInto
End Sub
It doesn't pull anything, the textbox on my main form is blank.
Take a look here:
SCCMReports = New ReportSettings
UserData.text = SCCMReports.UserSignedInto
When was the SCCMReports form ever displayed to the user? Since it was never displayed, its tbUSI.Text value will of course be empty because the user never had an opportunity to enter text.
It sounds like you need a reference to an existing instance of ReportSettings, rather than creating a new instance. Where do you have that existing instance?
If Form1 created the instance in another block of code, store it in a class-level member on Form1 (perhaps called SCCMReportsInstance or something of that nature). When the instance is created, set it to the value of that property and reference that property in your code:
UserData.text = Me.SCCMReportsInstance.UserSignedInto
If the ReportSettings form is instead creating the instance of Form1 then it can pass a reference to itself. You'd still have a property on Form1, it would just be set in the constructor. Something like this:
Sub New(ByVal sccmReportsInstance As ReportSettings)
Me.SCCMReportsInstance = sccmReportsInstance
End Sub
So when initializing the Form1 instance, you'd pass the reference:
Dim form1 As Form1
form1 = New Form1(Me)
form1.Show()
Any way you go about it, you need to access the existing instance of the displayed form in order to access its properties. A new instance would have new versions of those properties and wouldn't have the same values.
Related
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
First of all, Why are forms classes?
But now on to the main question.
I have:
Form1.vb
Module1.vb
On the form there is a textbox, progress bar, labels etc.
I want to be able to change the properties of these objects on my form from module1, but I cant seem to access them.
These things on the form are objects, right? So do they have a certain scope? and how can I change it?
Wait but according to my solution explorer, these things are properties of a class??
But the form shows up when I run the program?? Wouldn't the form class have to be instantiated so that the form1 object is created?
Not that it matters, but here is a snippet from module1
Sub WriteObjectsToCSV()
Dim props As PropertyInfo() = MyCompanies(1).GetType().GetProperties()
Dim sw As StreamWriter =
My.Computer.FileSystem.OpenTextFileWriter(SaveAs, False)
Dim csv As New CsvHelper.CsvWriter(sw)
csv.WriteHeader(Of Company)()
csv.NextRecord()
For Each company In MyCompanies
'>>> want to write to my text box and change my progress bar here <<<
For Each prop In props
csv.WriteField(prop.GetValue(company))
Next
csv.NextRecord()
Next
End Sub
Forms are classes because they are created dynamically. You can instantiate and open the same form class serveral times and leave the instances open at the same time.
VB automatically instantiates the main form.
You can access the open forms through My.Application.OpenForms. The main form is always the first
Dim mainForm As Form1
mainForm = DirectCast(My.Application.OpenForms(0), Form1)
mainForm.txtOutput.Text = "hello"
To be able to access the controls of the form from outside, they must be declared Public or Internal. You can change the access modifier from the properties window (Modifiers property).
Instead, you can also declare a property in the form to make the text accessible outside
Public Property OutputText() As String
Get
Return txtOutput.Text
End Get
Set(ByVal value As String)
txtOutput.Text = value
End Set
End Property
Now you can write this in the module
mainForm.OutputText = "hello"
I'm building a small VB.net app. I want to add a little database (about 5 columns, 20 records). I want to keep everything in a single exe. I think it's a bit overkill to add a 'full' database, so I'm looking for an alternative.
I could create a CSV file, and add it as a resource. Is this a good idea, or are there any other better alternatives?
Another option for such a small amount of data is to store it in ApplicationSettings. Your question implies you are using WinForms, so you can make use of the built-in features with just a small amount of work to store your own custom class.
Create a class to represent your data.
Wrap that class in a property of another class that inherits from ApplicationSettingsBase as a List(Of )
Manipulate this custom setting as needed and call Save() as needed.
Here is an example that binds to a DataGrid:
The class that represents your data:
Public Class Fruit
Public Property FruitName As String
Public Property FruitColor As String
Public Property FruitGrowsOn As String
End Class
The class that turns Fruit into a collection stored in application settings. Notice it inherits ApplicationSettingsBase. Also notice the attributes on the Fruits property that identify this as a user setting as opposed to an application setting (which cannot be modified by the user). The DefaultSettingAttribute makes sure the collection is instantiated so you don't get null reference exception until after the first time you add an item:
Imports System.Configuration
Public NotInheritable Class FruitCollection
Inherits ApplicationSettingsBase
<UserScopedSettingAttribute()>
<DefaultSettingValue("")>
Public Property Fruits() As List(Of Fruit)
Get
Fruits = Me("Fruits")
End Get
Set(ByVal value As List(Of Fruit))
Me("Fruits") = value
End Set
End Property
End Class
The Form definition. Retrieves the instance of your custom setting (FruitUserSettings), creates a binding source for a DataGridView, and provides a Save button to persist the changes made in the grid to Settings. Next time the user opens the form the changes will still be there provided they clicked the Save button:
Public Class Form1
Dim FruitUserSettings As FruitCollection
Dim GridBindingSrc As BindingSource
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
FruitUserSettings = New FruitCollection()
GridBindingSrc = New BindingSource(FruitUserSettings, "Fruits")
DataGridView1.AutoGenerateColumns = True
DataGridView1.DataSource = GridBindingSrc
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
FruitUserSettings.Save()
End Sub
Private Sub Form1_FormClosing(sender As Object, e As FormClosingEventArgs) Handles MyBase.FormClosing
GridBindingSrc.Dispose()
End Sub
End Class
Note, you don't need a binding source or grid, these were just for demonstration. You can manipulate FruitUserSettings.Fruits like any other list in any way you want. As long as Save() is called on the settings you will retain the data.
You can download/clone the working sample here: https://github.com/crowcoder/CustomSetting
i would use XML file as little database, you can query it easily with linq (Language-Integrated Query). also there are built in library's that can help you handle you records and query's. of course that you can use access, excel (you can query excel with SQL) csv or txt file . also you can create a local data base file in visual studio
I have an MDI parent form that may open a child form called "Order". Order forms have a button that allows the user to print the order. The Order form has a print size variable defined at the beginning:
Public Class Order
Public psize As String
Private Sub button_order_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles process_order.Click
' Code to handle the order and then print, etc
Now the parent form has a psize variable as well, which is set to a default of "A4".
Only when someone clicks on one of the menu items on the Parent window's menu strip will this happen:
psize = "A6"
By default, whenever the parent window opens up a new Order form, I need it to set the child form's psize variable to its own psize value. Something like this:
Dim f As Form
f = New Order
f.MdiParent = Me
f.psize = Me.psize ' BUT THIS LINE DOESN'T WORK
f.Show()
I get the error that f.psize is not a member of the form.
I know that passing variables to and from the MDI parent and child is quite common but despite trying out a few options I saw here, it doesn't seem to be working. Is this the wrong approach?
The reason the property is not available is because you are using the wrong type for the variable. The base Form type does not define that property. Instead, your derived Order type does. You could do something like this:
Dim f As Order
f = New Order
f.MdiParent = Me
f.psize = Me.psize
f.Show()
UPDATE
As you have said in comments below, what you really need to do is to be able to share a dynamic setting between all your forms so that you can change the setting at any time and have it affect all your forms that have already been displayed. The best way to do that, would be to create a new class that stores all your shared settings, for instance:
Public Class Settings
Public PaperSize As String = "A6"
End Class
As you can see, by doing so, you can easily centralize all your default settings in your settings class, which is an added benefit. Then, you need to change the public property in your Order form to the new Settings type, for instance:
Public Class Order
Inherits Form
Public Settings As Settings
End Class
Then, you need to create your shared settings object in your MDI Parent form, and then pass it it to each of your Order forms as they are created:
Public Class MyParentForm
Private _settings As New Settings()
Private Sub ShowNewOrderForm()
Dim f As New Order()
f.MdiParent = Me
f.Settings = _settings
f.Show()
End Sub
Private Sub ChangePaperSize(size As String)
_settings.PaperSize = size
End Sub
End Class
Then, since the parent form and all the child Order forms share the same Settings object, and change made to that Settings object will be seen immediately by all the forms.
Change this:
Dim f As Form
to the actual implementation of your form:
Dim f As Order
or just the shortcut:
Dim f As New Order
When press F5 to compile a project, there are no errors or warnings but the form won't show up. What's up?
Every time that you try to run your code, it starts by creating an instance of frmMain, your default form and the one that is shown at application startup.
When this form is created, it automatically instantiates an instance of Form3 because you instantiate a variable of that type called modifyForm at the top of this form's code file:
Dim modifyForm As New Form3 'modify student
The problem is that, when the runtime goes to instantiate an object of type Form3, it gets called right back to where it was because of this statement at the top of the Form3 code file:
Dim frmMain As New frmMain
Rinse, lather, and repeat. Your code turns into an infinite loop, trying to instantiate an instance of frmMain, which tries to instantiate an instance of Form3, which tries to instantiate an instance of frmMain, ad nauseum. Eventually, this will overflow your available memory and cause a StackOverflowException.
It's important to note that all of this happens before the default instance of frmMain is even shown, because these variables are declared outside of any methods in your code. Because the computer never can escape this infinite loop, it never gets a chance to move on and actually display your form.
And the moment you've all been reading so patiently for:
Fix it by removing the declaration of frmMain at the top of the Form3 code file. I don't know what that's there for, anyway.
EDIT: Hopefully, I can clear up a little confusion regarding passing values between forms. Upon further study of your code, my instincts tell me that the best solution for you is to overload the constructor for Form3 to accept the calling form (the existing instance of frmMain) as an argument. This will allow you to access all of the public members of frmMain from within your Form3 class.
Here's a rough sketch of how you might do this in your code:
Public Class frmMain
''#The private data field that stores the shared data
Private _mySharedData As String = "This is the data I want to share across forms."
''#A public property to expose your shared data
''#that can be accessed by your Form3 object
Public Property MySharedData As String
Get
Return _mySharedData
End Get
Set(ByVal value As String)
_mySharedData = value
End Set
End Property
Private Sub frmMain_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
''#Do all of your other stuff here...
''#Create a new instance of Form3, specifying this form as its caller
Dim otherForm As New Form3(Me)
''#Show the new instance of Form3
otherForm.Show()
End Sub
End Class
Public Class Form3
''#The private field that holds the reference to the main form
''#that you want to be able to access data from
Private myMainForm As frmMain
Public Sub New(ByVal callingForm As frmMain)
InitializeComponent()
''#Save the reference to the calling form so you can use it later
myMainForm = callingForm
End Sub
Private Sub Form3_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
''#Access anything that you need from the main form
MessageBox.Show(myMainForm.MySharedData)
End Sub
End Class
As you can see, frmMain exposes a public property (backed by a correspondingly-named private variable) called MySharedData. This can be absolutely anything you want, and you can have as many of these as you want.
Also notice that how the constructor (the New method) for Form3 accepts an instance of frmMain as an argument. Whenever you create a new Form3 object from frmMain, you just specify Me, which indicates that you want to pass the current instance of frmMain. In the constructor method, Form3 stores that reference to its calling form away, and you can use this reference any time you like in Form3's code to access the public properties exposed by frmMain.
In VS2010 menu, go to Build -> Configuration Manager, does your project have the checkbox in the "Build" column enabled?
If it's project upgraded from an older Visual Studio version it may be that it is not targeting .NET Framework 4.0. In that case you should change it as explained here.
To analyze the problem press F8 (or F10, depends on your default keyboard settings) to step into the code instead of running the app. This should take you to the main method where the main form would be initialized.